first tests ran, working to make takeover height unnecessary
This commit is contained in:
parent
3e16229318
commit
c2d2e4befd
12 changed files with 1075 additions and 1098 deletions
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#include <claimtrie.h>
|
#include <claimtrie.h>
|
||||||
#include <hash.h>
|
#include <hash.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
|
@ -54,8 +53,7 @@ CClaimTrie::CClaimTrie(bool fMemory, bool fWipe, int height, int proportionalDel
|
||||||
_db.define("merkle_pair", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); });
|
_db.define("merkle_pair", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); });
|
||||||
_db.define("merkle", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); });
|
_db.define("merkle", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); });
|
||||||
|
|
||||||
_db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, "
|
_db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT, hash BLOB)";
|
||||||
"lastTakeoverHeight INTEGER NOT NULL DEFAULT 0, hash BLOB)";
|
|
||||||
_db << "CREATE INDEX nodes_hash ON nodes (hash)";
|
_db << "CREATE INDEX nodes_hash ON nodes (hash)";
|
||||||
_db << "CREATE INDEX nodes_parent ON nodes (parent)";
|
_db << "CREATE INDEX nodes_parent ON nodes (parent)";
|
||||||
|
|
||||||
|
@ -110,15 +108,17 @@ bool CClaimTrie::empty() {
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& outPoint) const
|
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& outPoint) const
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT 1 FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? AND validHeight < ? LIMIT 1"
|
auto query = base->_db << "SELECT 1 FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? "
|
||||||
<< name << outPoint.hash << outPoint.n << nNextHeight;
|
"AND validHeight < ? AND expirationHeight >= ? LIMIT 1"
|
||||||
|
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight;
|
||||||
return query.begin() != query.end();
|
return query.begin() != query.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const COutPoint& outPoint) const
|
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const COutPoint& outPoint) const
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT 1 FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? AND validHeight < ? LIMIT 1"
|
auto query = base->_db << "SELECT 1 FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? "
|
||||||
<< name << outPoint.hash << outPoint.n << nNextHeight;
|
"AND validHeight < ? AND expirationHeight >= ? LIMIT 1"
|
||||||
|
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight;
|
||||||
return query.begin() != query.end();
|
return query.begin() != query.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
|
||||||
{
|
{
|
||||||
// includes values that are not yet valid
|
// includes values that are not yet valid
|
||||||
auto query = base->_db << "SELECT supportedClaimID, txID, txN, blockHeight, validHeight, amount "
|
auto query = base->_db << "SELECT supportedClaimID, txID, txN, blockHeight, validHeight, amount "
|
||||||
"FROM supports WHERE nodeName = ?" << name;
|
"FROM supports WHERE nodeName = ? AND expirationHeight >= ?" << name << nNextHeight;
|
||||||
supportEntryType ret;
|
supportEntryType ret;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
CSupportValue value;
|
CSupportValue value;
|
||||||
|
@ -139,8 +139,9 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
|
bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT validHeight FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? AND validHeight >= ? LIMIT 1"
|
auto query = base->_db << "SELECT validHeight FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? "
|
||||||
<< name << outPoint.hash << outPoint.n << nNextHeight;
|
"AND validHeight >= ? AND expirationHeight >= ? LIMIT 1"
|
||||||
|
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
row >> nValidAtHeight;
|
row >> nValidAtHeight;
|
||||||
return true;
|
return true;
|
||||||
|
@ -150,8 +151,9 @@ bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const COutPo
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
|
bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT validHeight FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? AND validHeight >= ? LIMIT 1"
|
auto query = base->_db << "SELECT validHeight FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? "
|
||||||
<< name << outPoint.hash << outPoint.n << nNextHeight;
|
"AND validHeight >= ? AND expirationHeight >= ? LIMIT 1"
|
||||||
|
<< name << outPoint.hash << outPoint.n << nNextHeight << nNextHeight;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
row >> nValidAtHeight;
|
row >> nValidAtHeight;
|
||||||
return true;
|
return true;
|
||||||
|
@ -172,7 +174,8 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
|
||||||
if (name.empty()) return false;
|
if (name.empty()) return false;
|
||||||
// to remove a node it must have one or less children and no claims
|
// to remove a node it must have one or less children and no claims
|
||||||
vector_builder<std::string, std::string> claimsBuilder;
|
vector_builder<std::string, std::string> claimsBuilder;
|
||||||
base->_db << "SELECT name FROM claims WHERE name = ?" << name >> claimsBuilder;
|
base->_db << "SELECT name FROM claims WHERE name = ? AND validHeight < ? AND expirationHeight >= ? "
|
||||||
|
<< name << nNextHeight << nNextHeight >> claimsBuilder;
|
||||||
claims = std::move(claimsBuilder);
|
claims = std::move(claimsBuilder);
|
||||||
if (!claims.empty()) return false; // still has claims
|
if (!claims.empty()) return false; // still has claims
|
||||||
// we now know it has no claims, but we need to check its children
|
// we now know it has no claims, but we need to check its children
|
||||||
|
@ -210,9 +213,10 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
|
||||||
// should we do the same to remove nodes? no; we need their last takeover height if they come back
|
// should we do the same to remove nodes? no; we need their last takeover height if they come back
|
||||||
//float time = 0;
|
//float time = 0;
|
||||||
|
|
||||||
|
// assume parents are not set correctly here:
|
||||||
auto parentQuery = base->_db << "SELECT name FROM nodes WHERE parent IS NOT NULL AND "
|
auto parentQuery = base->_db << "SELECT name FROM nodes WHERE parent IS NOT NULL AND "
|
||||||
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
||||||
"SELECT SUBSTR(p, 0, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
"SELECT SUBSTR(p, 1, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
||||||
"ORDER BY LENGTH(name) DESC LIMIT 1";
|
"ORDER BY LENGTH(name) DESC LIMIT 1";
|
||||||
|
|
||||||
for (auto& name: names) {
|
for (auto& name: names) {
|
||||||
|
@ -276,40 +280,50 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
|
||||||
if (splitPos == 0)
|
if (splitPos == 0)
|
||||||
base->_db << "UPDATE nodes SET hash = NULL WHERE name = ?" << parent;
|
base->_db << "UPDATE nodes SET hash = NULL WHERE name = ?" << parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// now we need to percolate the nulls up the tree
|
||||||
|
// parents should all be set right
|
||||||
|
base->_db << "UPDATE nodes SET hash = NULL WHERE name IN (WITH RECURSIVE prefix(p) AS ("
|
||||||
|
"SELECT parent WHERE hash IS NULL ORDER BY name DESC UNION "
|
||||||
|
"SELECT parent FROM prefix,nodes WHERE name = p AND p IS NOT NULL)";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t CClaimTrieCacheBase::getTotalNamesInTrie() const
|
std::size_t CClaimTrieCacheBase::getTotalNamesInTrie() const
|
||||||
{
|
{
|
||||||
// you could do this select from the nodes table, but you would have to ensure it is not dirty first
|
// you could do this select from the nodes table, but you would have to ensure it is not dirty first
|
||||||
std::size_t ret;
|
std::size_t ret;
|
||||||
base->_db << "SELECT COUNT(DISTINCT nodeName) FROM claims" >> ret;
|
base->_db << "SELECT COUNT(DISTINCT nodeName) FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
|
||||||
|
<< nNextHeight << nNextHeight >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
|
std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
|
||||||
{
|
{
|
||||||
std::size_t ret;
|
std::size_t ret;
|
||||||
base->_db << "SELECT COUNT(*) FROM claims" >> ret;
|
base->_db << "SELECT COUNT(*) FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
|
||||||
|
<< nNextHeight << nNextHeight >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
|
CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
|
||||||
{
|
{
|
||||||
CAmount ret = 0;
|
CAmount ret = 0;
|
||||||
std::string query("SELECT c.amount + SUM(SELECT s.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?)"
|
std::string query("SELECT c.amount + SUM(SELECT s.amount FROM supports s "
|
||||||
" FROM claims c WHERE c.validHeight < ?");
|
"WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) "
|
||||||
|
"FROM claims c WHERE c.validHeight < ? AND s.expirationHeight >= ?");
|
||||||
if (fControllingOnly)
|
if (fControllingOnly)
|
||||||
throw std::runtime_error("not implemented yet"); // TODO: finish this
|
throw std::runtime_error("not implemented yet"); // TODO: finish this
|
||||||
base->_db << query << nNextHeight << nNextHeight >> ret;
|
base->_db << query << nNextHeight << nNextHeight << nNextHeight << nNextHeight >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim) const
|
bool CClaimTrieCacheBase::getInfoForName(const std::string& name, CClaimValue& claim) const
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT c.claimID, c.txID, c.txN, c.blockHeight, c.validHeight, c.amount, c.amount + "
|
auto query = base->_db << "SELECT c.claimID, c.txID, c.txN, c.blockHeight, c.validHeight, c.amount, "
|
||||||
"SUM(SELECT s.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?) as effectiveAmount"
|
"(SELECT TOTAL(s.amount)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount "
|
||||||
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? "
|
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
|
||||||
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1" << nNextHeight << name << nNextHeight;
|
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1"
|
||||||
|
<< nNextHeight << nNextHeight << name << nNextHeight << nNextHeight;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
|
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
|
||||||
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount;
|
>> claim.nHeight >> claim.nValidAtHeight >> claim.nAmount >> claim.nEffectiveAmount;
|
||||||
|
@ -325,8 +339,8 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
|
||||||
auto supports = getSupportsForName(name);
|
auto supports = getSupportsForName(name);
|
||||||
|
|
||||||
auto query = base->_db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount "
|
auto query = base->_db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount "
|
||||||
"FROM claims WHERE nodeName = ?"
|
"FROM claims WHERE nodeName = ? AND expirationHeight >= ?"
|
||||||
<< name;
|
<< name << nNextHeight;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
CClaimValue claim;
|
CClaimValue claim;
|
||||||
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
|
row >> claim.claimId >> claim.outPoint.hash >> claim.outPoint.n
|
||||||
|
@ -369,19 +383,18 @@ void completeHash(uint256& partialHash, const std::string& key, std::size_t to)
|
||||||
.Finalize(partialHash.begin());
|
.Finalize(partialHash.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly)
|
uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, bool checkOnly)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> vchToHash;
|
std::vector<uint8_t> vchToHash;
|
||||||
const auto pos = name.size();
|
const auto pos = name.size();
|
||||||
auto query = base->_db << "SELECT name, hash, lastTakeoverHeight FROM nodes WHERE parent = ? ORDER BY name" << name;
|
auto query = base->_db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name;
|
||||||
for (auto&& row : query) {
|
for (auto&& row : query) {
|
||||||
std::string key;
|
std::string key;
|
||||||
int keyLastTakeoverHeight;
|
|
||||||
std::unique_ptr<uint256> hash;
|
std::unique_ptr<uint256> hash;
|
||||||
row >> key >> hash >> keyLastTakeoverHeight;
|
row >> key >> hash;
|
||||||
if (hash == nullptr) hash = std::make_unique<uint256>();
|
if (hash == nullptr) hash = std::make_unique<uint256>();
|
||||||
if (hash->IsNull()) {
|
if (hash->IsNull()) {
|
||||||
*hash = recursiveComputeMerkleHash(key, keyLastTakeoverHeight, checkOnly);
|
*hash = recursiveComputeMerkleHash(key, checkOnly);
|
||||||
}
|
}
|
||||||
completeHash(*hash, key, pos);
|
completeHash(*hash, key, pos);
|
||||||
vchToHash.push_back(key[pos]);
|
vchToHash.push_back(key[pos]);
|
||||||
|
@ -390,11 +403,11 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
|
||||||
|
|
||||||
CClaimValue claim;
|
CClaimValue claim;
|
||||||
if (getInfoForName(name, claim)) {
|
if (getInfoForName(name, claim)) {
|
||||||
uint256 valueHash = getValueHash(claim.outPoint, lastTakeoverHeight);
|
uint256 valueHash = getValueHash(claim.outPoint, claim.nValidAtHeight);
|
||||||
vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
|
vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto computedHash = Hash(vchToHash.begin(), vchToHash.end());
|
auto computedHash = vchToHash.empty() ? one : Hash(vchToHash.begin(), vchToHash.end());
|
||||||
if (!checkOnly)
|
if (!checkOnly)
|
||||||
base->_db << "UPDATE nodes SET hash = ? WHERE name = ?" << computedHash << name;
|
base->_db << "UPDATE nodes SET hash = ? WHERE name = ?" << computedHash << name;
|
||||||
return computedHash;
|
return computedHash;
|
||||||
|
@ -404,13 +417,12 @@ bool CClaimTrieCacheBase::checkConsistency()
|
||||||
{
|
{
|
||||||
// verify that all claims hash to the values on the nodes
|
// verify that all claims hash to the values on the nodes
|
||||||
|
|
||||||
auto query = base->_db << "SELECT name, hash, lastTakeoverHeight FROM nodes";
|
auto query = base->_db << "SELECT name, hash FROM nodes";
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
std::string name;
|
std::string name;
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
int takeoverHeight;
|
row >> name >> hash;
|
||||||
row >> name >> hash >> takeoverHeight;
|
auto computedHash = recursiveComputeMerkleHash(name, true);
|
||||||
auto computedHash = recursiveComputeMerkleHash(name, takeoverHeight, true);
|
|
||||||
if (computedHash != hash)
|
if (computedHash != hash)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -475,11 +487,10 @@ int CClaimTrieCacheBase::expirationTime() const
|
||||||
uint256 CClaimTrieCacheBase::getMerkleHash()
|
uint256 CClaimTrieCacheBase::getMerkleHash()
|
||||||
{
|
{
|
||||||
ensureTreeStructureIsUpToDate();
|
ensureTreeStructureIsUpToDate();
|
||||||
int lastTakeover;
|
|
||||||
std::unique_ptr<uint256> hash;
|
std::unique_ptr<uint256> hash;
|
||||||
base->_db << "SELECT hash, lastTakeoverHeight FROM nodes WHERE name = ''" >> std::tie(hash, lastTakeover);
|
base->_db << "SELECT hash FROM nodes WHERE name = ''" >> hash;
|
||||||
if (hash == nullptr || hash->IsNull())
|
if (hash == nullptr || hash->IsNull())
|
||||||
return recursiveComputeMerkleHash("", lastTakeover, false);
|
return recursiveComputeMerkleHash("", false);
|
||||||
return *hash;
|
return *hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,7 +512,9 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out
|
||||||
auto expires = expirationTime() + nHeight;
|
auto expires = expirationTime() + nHeight;
|
||||||
auto validHeight = nHeight + delay;
|
auto validHeight = nHeight + delay;
|
||||||
base->_db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
|
base->_db << "INSERT INTO claims(claimID, name, nodeName, txID, txN, amount, blockHeight, validHeight, expirationHeight, metadata) "
|
||||||
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" << claimId << name << nodeName
|
"VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(claimID) DO UPDATE SET name = excluded.name, "
|
||||||
|
"nodeName = excluded.nodeName, txID = excluded.txID, txN = excluded.txN, amount = excluded.amount, "
|
||||||
|
"expirationHeight = excluded.expirationHeight, metadata = excluded.metadata" << claimId << name << nodeName
|
||||||
<< outPoint.hash << outPoint.n << nAmount << nHeight << validHeight << expires << metadata;
|
<< outPoint.hash << outPoint.n << nAmount << nHeight << validHeight << expires << metadata;
|
||||||
|
|
||||||
base->_db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName;
|
base->_db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << nodeName;
|
||||||
|
@ -837,7 +850,7 @@ static const boost::container::flat_map<std::pair<int, std::string>, int> takeov
|
||||||
{{ 653524, "celtic-folk-music-full-live-concert-mps" }, 589762},
|
{{ 653524, "celtic-folk-music-full-live-concert-mps" }, 589762},
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||||
{
|
{
|
||||||
// the plan:
|
// the plan:
|
||||||
// for every claim and support that becomes active this block set its node hash to null (aka, dirty)
|
// for every claim and support that becomes active this block set its node hash to null (aka, dirty)
|
||||||
|
@ -863,8 +876,6 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
|
||||||
expireUndo.emplace_back(name, value);
|
expireUndo.emplace_back(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base->_db << "UPDATE claims SET active = 0 WHERE expirationHeight = ?"
|
|
||||||
<< nNextHeight;
|
|
||||||
base->_db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM claims WHERE expirationHeight = ?)"
|
base->_db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM claims WHERE expirationHeight = ?)"
|
||||||
<< nNextHeight;
|
<< nNextHeight;
|
||||||
|
|
||||||
|
@ -880,54 +891,26 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimQueueR
|
||||||
expireSupportUndo.emplace_back(name, value);
|
expireSupportUndo.emplace_back(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base->_db << "UPDATE supports SET active = 0 WHERE expirationHeight = ?"
|
|
||||||
<< nNextHeight;
|
|
||||||
base->_db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)"
|
base->_db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)"
|
||||||
<< nNextHeight;
|
<< nNextHeight;
|
||||||
|
|
||||||
// takeover handling:
|
// takeover handling:
|
||||||
std::vector<std::pair<std::string, int>> takeovers;
|
vector_builder<std::string, std::string> takeovers;
|
||||||
base->_db << "SELECT name, lastTakeoverHeight FROM nodes WHERE hash IS NULL" >> takeovers;
|
base->_db << "SELECT name FROM nodes WHERE hash IS NULL" >> takeovers;
|
||||||
|
|
||||||
for (const auto& takeover : takeovers) {
|
|
||||||
// the plan: select the old and new bests
|
|
||||||
// if they are different, record the valid heights of the current claims that are not active
|
|
||||||
// then make them all active
|
|
||||||
|
|
||||||
|
for (const auto& nameWithTakeover : takeovers) {
|
||||||
if (nNextHeight >= 496856 && nNextHeight <= 653524) {
|
if (nNextHeight >= 496856 && nNextHeight <= 653524) {
|
||||||
auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, takeover.first));
|
auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover));
|
||||||
if (wit != takeoverWorkarounds.end()) {
|
if (wit != takeoverWorkarounds.end()) {
|
||||||
activateAllFor(insertUndo, insertSupportUndo, takeover.first);
|
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover);
|
||||||
base->_db << "UPDATE nodes SET lastTakeoverHeight = ? WHERE nodeName = ?" << wit->second << takeover.first;
|
|
||||||
takeoverHeightUndo.emplace_back(takeover.first, takeover.second);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int lastTakeoverHeight = 0;
|
// if somebody activates on this block and they are the new best, then everybody activates on this block
|
||||||
auto findBestValid = base->_db << "SELECT c.validHeight, c.amount + "
|
CClaimValue value;
|
||||||
"SUM(SELECT s.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?) as effectiveAmount"
|
if (getInfoForName(nameWithTakeover, value) && value.nValidAtHeight == nNextHeight - 1)
|
||||||
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? "
|
activateAllFor(insertUndo, insertSupportUndo, nameWithTakeover);
|
||||||
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN LIMIT 1"
|
|
||||||
<< nNextHeight + 1 << takeover.first << nNextHeight + 1;
|
|
||||||
|
|
||||||
auto lit = findBestValid.begin();
|
|
||||||
if (lit == findBestValid.end()) {
|
|
||||||
takeoverHeightUndo.emplace_back(takeover.first, takeover.second);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*lit >> lastTakeoverHeight;
|
|
||||||
if (lastTakeoverHeight == takeover.second)
|
|
||||||
continue; // no takeover happened
|
|
||||||
activateAllFor(insertUndo, insertSupportUndo, takeover.first);
|
|
||||||
|
|
||||||
// now get the best again:
|
|
||||||
findBestValid++;
|
|
||||||
lit = findBestValid.begin();
|
|
||||||
*lit >> lastTakeoverHeight;
|
|
||||||
base->_db << "UPDATE nodes SET lastTakeoverHeight = ? WHERE nodeName = ?" << lastTakeoverHeight << takeover.first;
|
|
||||||
|
|
||||||
takeoverHeightUndo.emplace_back(takeover.first, takeover.second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nNextHeight++;
|
nNextHeight++;
|
||||||
|
@ -938,8 +921,8 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
// now that we know a takeover is happening, we bring everybody in:
|
// now that we know a takeover is happening, we bring everybody in:
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ? AND validHeight > ?"
|
auto query = base->_db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ? AND validHeight > ? AND expirationHeight >= ?"
|
||||||
<< name << nNextHeight;
|
<< name << nNextHeight << nNextHeight;
|
||||||
for (auto &&row: query) {
|
for (auto &&row: query) {
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
@ -949,12 +932,13 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// and then update them all to activate now:
|
// and then update them all to activate now:
|
||||||
base->_db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND validHeight > ?" << nNextHeight << name << nNextHeight;
|
base->_db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND validHeight > ? AND expirationHeight >= ?"
|
||||||
|
<< nNextHeight << name << nNextHeight << nNextHeight;
|
||||||
|
|
||||||
// then do the same for supports:
|
// then do the same for supports:
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ? AND validHeight > ?"
|
auto query = base->_db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ? AND validHeight > ? AND expirationHeight >= ?"
|
||||||
<< name << nNextHeight;
|
<< name << nNextHeight << nNextHeight;
|
||||||
for (auto &&row: query) {
|
for (auto &&row: query) {
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
@ -964,7 +948,8 @@ void CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// and then update them all to activate now:
|
// and then update them all to activate now:
|
||||||
base->_db << "UPDATE supports SET validHeight = ? WHERE nodeName = ? AND validHeight > ?" << nNextHeight << name << nNextHeight;
|
base->_db << "UPDATE supports SET validHeight = ? WHERE nodeName = ? AND validHeight > ? AND expirationHeight >= ?"
|
||||||
|
<< nNextHeight << name << nNextHeight << nNextHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||||
|
@ -998,12 +983,8 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimQueueR
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheBase::finalizeDecrement()
|
||||||
{
|
{
|
||||||
for (auto it = takeoverHeightUndo.crbegin(); it != takeoverHeightUndo.crend(); ++it)
|
|
||||||
base->_db << "UPDATE nodes SET lastTakeoverHeight = ?, hash = NULL WHERE name = ?"
|
|
||||||
<< it->second << it->first;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,11 +1154,11 @@ int CClaimTrieCacheBase::getNumBlocksOfContinuousOwnership(const std::string& na
|
||||||
if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end())
|
if (nNextHeight <= 646584 && ownershipWorkaround.find(std::make_pair(nNextHeight, name)) != ownershipWorkaround.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int lastTakeover = -1;
|
CClaimValue value;
|
||||||
auto query = base->_db << "SELECT lastTakeoverHeight FROM nodes WHERE name = ?" << name;
|
if (getInfoForName(name, value))
|
||||||
for (auto&& row: query)
|
return nNextHeight - value.nValidAtHeight;
|
||||||
row >> lastTakeover;
|
|
||||||
return lastTakeover > 0 ? nNextHeight - lastTakeover : 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CClaimTrieCacheBase::getDelayForName(const std::string& name) const
|
int CClaimTrieCacheBase::getDelayForName(const std::string& name) const
|
||||||
|
@ -1207,19 +1188,18 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160
|
||||||
// cache the parent nodes
|
// cache the parent nodes
|
||||||
getMerkleHash();
|
getMerkleHash();
|
||||||
proof = CClaimTrieProof();
|
proof = CClaimTrieProof();
|
||||||
auto nodeQuery = base->_db << "SELECT name, lastTakeoverHeight FROM nodes WHERE "
|
auto nodeQuery = base->_db << "SELECT name FROM nodes WHERE "
|
||||||
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
||||||
"SELECT SUBSTR(p, 0, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
"SELECT SUBSTR(p, 1, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
||||||
"ORDER BY LENGTH(name)" << name;
|
"ORDER BY LENGTH(name)" << name;
|
||||||
for (auto&& row: nodeQuery) {
|
for (auto&& row: nodeQuery) {
|
||||||
CClaimValue claim;
|
CClaimValue claim;
|
||||||
std::string key;
|
std::string key;
|
||||||
int lastTakeoverHeight;
|
row >> key;
|
||||||
row >> key >> lastTakeoverHeight;
|
|
||||||
bool fNodeHasValue = getInfoForName(key, claim);
|
bool fNodeHasValue = getInfoForName(key, claim);
|
||||||
uint256 valueHash;
|
uint256 valueHash;
|
||||||
if (fNodeHasValue)
|
if (fNodeHasValue)
|
||||||
valueHash = getValueHash(claim.outPoint, lastTakeoverHeight);
|
valueHash = getValueHash(claim.outPoint, claim.nValidAtHeight);
|
||||||
|
|
||||||
const auto pos = key.size();
|
const auto pos = key.size();
|
||||||
std::vector<std::pair<unsigned char, uint256>> children;
|
std::vector<std::pair<unsigned char, uint256>> children;
|
||||||
|
@ -1246,7 +1226,7 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160
|
||||||
proof.hasValue = fNodeHasValue && claim.claimId == finalClaim;
|
proof.hasValue = fNodeHasValue && claim.claimId == finalClaim;
|
||||||
if (proof.hasValue) {
|
if (proof.hasValue) {
|
||||||
proof.outPoint = claim.outPoint;
|
proof.outPoint = claim.outPoint;
|
||||||
proof.nHeightOfLastTakeover = lastTakeoverHeight;
|
proof.nHeightOfLastTakeover = claim.nValidAtHeight;
|
||||||
}
|
}
|
||||||
valueHash.SetNull();
|
valueHash.SetNull();
|
||||||
}
|
}
|
||||||
|
@ -1256,12 +1236,14 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheBase::findNameForClaim(const std::vector<unsigned char>& claim, CClaimValue& value, std::string& name) {
|
bool CClaimTrieCacheBase::findNameForClaim(const std::vector<unsigned char>& claim, CClaimValue& value, std::string& name) {
|
||||||
auto query = base->_db << "SELECT nodeName, claimId, txID, txN, amount, block_height FROM claims WHERE SUBSTR(claimID, 1, ?) = ?" << claim.size() + 1 << claim;
|
auto query = base->_db << "SELECT nodeName, claimId, txID, txN, amount, validHeight, block_height "
|
||||||
|
"FROM claims WHERE SUBSTR(claimID, 1, ?) = ? AND validHeight < ? AND expirationHeight >= ?"
|
||||||
|
<< claim.size() + 1 << claim << nNextHeight << nNextHeight;
|
||||||
auto hit = false;
|
auto hit = false;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
if (hit) return false;
|
if (hit) return false;
|
||||||
row >> name >> value.claimId >> value.outPoint.hash >> value.outPoint.n
|
row >> name >> value.claimId >> value.outPoint.hash >> value.outPoint.n
|
||||||
>> value.nAmount >> value.nHeight;
|
>> value.nAmount >> value.nValidAtHeight >> value.nHeight;
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1269,7 +1251,8 @@ bool CClaimTrieCacheBase::findNameForClaim(const std::vector<unsigned char>& cla
|
||||||
|
|
||||||
void CClaimTrieCacheBase::getNamesInTrie(std::function<void(const std::string&)> callback)
|
void CClaimTrieCacheBase::getNamesInTrie(std::function<void(const std::string&)> callback)
|
||||||
{
|
{
|
||||||
auto query = base->_db << "SELECT DISTINCT nodeName FROM claims";
|
auto query = base->_db << "SELECT DISTINCT nodeName FROM claims WHERE validHeight < ? AND expirationHeight >= ?"
|
||||||
|
<< nNextHeight << nNextHeight;
|
||||||
for (auto&& row: query) {
|
for (auto&& row: query) {
|
||||||
std::string name;
|
std::string name;
|
||||||
row >> name;
|
row >> name;
|
||||||
|
|
|
@ -49,19 +49,21 @@ namespace sqlite {
|
||||||
struct has_sqlite_type<uint160, SQLITE_BLOB, void> : std::true_type {};
|
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>) {
|
inline uint160 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint160>) {
|
||||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
|
||||||
uint160 ret;
|
uint160 ret;
|
||||||
assert(bytes == ret.size());
|
|
||||||
auto ptr = sqlite3_column_blob(stmt, inx);
|
auto ptr = sqlite3_column_blob(stmt, inx);
|
||||||
|
if (!ptr) return ret;
|
||||||
|
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||||
|
assert(bytes == ret.size());
|
||||||
std::memcpy(ret.begin(), ptr, bytes);
|
std::memcpy(ret.begin(), ptr, bytes);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint256>) {
|
inline uint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint256>) {
|
||||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
|
||||||
uint256 ret;
|
uint256 ret;
|
||||||
assert(bytes == ret.size());
|
|
||||||
auto ptr = sqlite3_column_blob(stmt, inx);
|
auto ptr = sqlite3_column_blob(stmt, inx);
|
||||||
|
if (!ptr) return ret;
|
||||||
|
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||||
|
assert(bytes == ret.size());
|
||||||
std::memcpy(ret.begin(), ptr, bytes);
|
std::memcpy(ret.begin(), ptr, bytes);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -373,8 +375,7 @@ public:
|
||||||
virtual bool incrementBlock(insertUndoType& insertUndo,
|
virtual bool incrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
insertUndoType& insertSupportUndo,
|
insertUndoType& insertSupportUndo,
|
||||||
supportQueueRowType& expireSupportUndo,
|
supportQueueRowType& expireSupportUndo);
|
||||||
std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
|
|
||||||
|
|
||||||
virtual bool decrementBlock(insertUndoType& insertUndo,
|
virtual bool decrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
|
@ -386,7 +387,7 @@ public:
|
||||||
|
|
||||||
virtual int expirationTime() const;
|
virtual int expirationTime() const;
|
||||||
|
|
||||||
virtual bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
|
virtual bool finalizeDecrement();
|
||||||
|
|
||||||
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
|
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
|
||||||
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
|
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
|
||||||
|
@ -403,7 +404,7 @@ protected:
|
||||||
CClaimTrie* base;
|
CClaimTrie* base;
|
||||||
bool dirtyNodes;
|
bool dirtyNodes;
|
||||||
|
|
||||||
virtual uint256 recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly);
|
virtual uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly);
|
||||||
|
|
||||||
supportEntryType getSupportsForName(const std::string& name) const;
|
supportEntryType getSupportsForName(const std::string& name) const;
|
||||||
|
|
||||||
|
@ -435,13 +436,12 @@ public:
|
||||||
int expirationTime() const override;
|
int expirationTime() const override;
|
||||||
|
|
||||||
virtual void initializeIncrement();
|
virtual void initializeIncrement();
|
||||||
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
|
bool finalizeDecrement() override;
|
||||||
|
|
||||||
bool incrementBlock(insertUndoType& insertUndo,
|
bool incrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
insertUndoType& insertSupportUndo,
|
insertUndoType& insertSupportUndo,
|
||||||
supportQueueRowType& expireSupportUndo,
|
supportQueueRowType& expireSupportUndo) override;
|
||||||
std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
|
|
||||||
|
|
||||||
bool decrementBlock(insertUndoType& insertUndo,
|
bool decrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
|
@ -470,8 +470,7 @@ public:
|
||||||
bool incrementBlock(insertUndoType& insertUndo,
|
bool incrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
insertUndoType& insertSupportUndo,
|
insertUndoType& insertSupportUndo,
|
||||||
supportQueueRowType& expireSupportUndo,
|
supportQueueRowType& expireSupportUndo) override;
|
||||||
std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
|
|
||||||
|
|
||||||
bool decrementBlock(insertUndoType& insertUndo,
|
bool decrementBlock(insertUndoType& insertUndo,
|
||||||
claimQueueRowType& expireUndo,
|
claimQueueRowType& expireUndo,
|
||||||
|
@ -497,12 +496,12 @@ public:
|
||||||
|
|
||||||
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
|
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
|
||||||
void initializeIncrement() override;
|
void initializeIncrement() override;
|
||||||
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
|
bool finalizeDecrement() override;
|
||||||
|
|
||||||
bool allowSupportMetadata() const;
|
bool allowSupportMetadata() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint256 recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly) override;
|
uint256 recursiveComputeMerkleHash(const std::string& name, bool checkOnly) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CClaimTrieCacheHashFork CClaimTrieCache;
|
typedef CClaimTrieCacheHashFork CClaimTrieCache;
|
||||||
|
|
|
@ -25,9 +25,9 @@ int CClaimTrieCacheExpirationFork::expirationTime() const
|
||||||
return nExpirationTime;
|
return nExpirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||||
{
|
{
|
||||||
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo)) {
|
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
|
||||||
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
|
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,9 @@ void CClaimTrieCacheExpirationFork::initializeIncrement()
|
||||||
forkForExpirationChange(true);
|
forkForExpirationChange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheExpirationFork::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheExpirationFork::finalizeDecrement()
|
||||||
{
|
{
|
||||||
auto ret = CClaimTrieCacheBase::finalizeDecrement(takeoverHeightUndo);
|
auto ret = CClaimTrieCacheBase::finalizeDecrement();
|
||||||
if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
|
if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
|
||||||
forkForExpirationChange(false);
|
forkForExpirationChange(false);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -74,7 +74,7 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
|
||||||
if (!increment) extension = -extension;
|
if (!increment) extension = -extension;
|
||||||
base->_db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << nNextHeight;
|
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 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)
|
base->_db << "UPDATE nodes SET hash = NULL"; // recompute all hashes (as there aren't that many at this point)
|
||||||
dirtyNodes = true;
|
dirtyNodes = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool f
|
||||||
|
|
||||||
base->_db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
base->_db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
||||||
|
|
||||||
auto query = base->_db << "SELECT NORMALIZED(name), name, claimID as nn FROM claims HAVING nodeName != nn";
|
auto query = base->_db << "SELECT NORMALIZED(name) as nn, name, claimID FROM claims HAVING nodeName != nn";
|
||||||
for(auto&& row: query) {
|
for(auto&& row: query) {
|
||||||
std::string newName, oldName;
|
std::string newName, oldName;
|
||||||
uint160 claimID;
|
uint160 claimID;
|
||||||
|
@ -143,17 +143,17 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool f
|
||||||
if (!forward) std::swap(newName, oldName);
|
if (!forward) std::swap(newName, oldName);
|
||||||
base->_db << "UPDATE claims SET nodeName = ? WHERE claimID = ?" << newName << claimID;
|
base->_db << "UPDATE claims SET nodeName = ? WHERE claimID = ?" << newName << claimID;
|
||||||
base->_db << "DELETE FROM nodes WHERE name = ?" << oldName;
|
base->_db << "DELETE FROM nodes WHERE name = ?" << oldName;
|
||||||
base->_db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT DO UPDATE hash = NULL, claimHash = NULL" << newName;
|
base->_db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT DO UPDATE hash = NULL" << newName;
|
||||||
}
|
}
|
||||||
dirtyNodes = true;
|
dirtyNodes = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||||
{
|
{
|
||||||
normalizeAllNamesInTrieIfNecessary(true);
|
normalizeAllNamesInTrieIfNecessary(true);
|
||||||
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo);
|
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||||
|
@ -196,36 +196,37 @@ CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieC
|
||||||
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
||||||
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
||||||
|
|
||||||
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly)
|
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, bool checkOnly)
|
||||||
{
|
{
|
||||||
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
||||||
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, lastTakeoverHeight, checkOnly);
|
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, checkOnly);
|
||||||
|
|
||||||
auto childQuery = base->_db << "SELECT name, hash, lastTakeoverHeight FROM nodes WHERE parent = ? ORDER BY name" << name;
|
auto childQuery = base->_db << "SELECT name, hash FROM nodes WHERE parent = ? ORDER BY name" << name;
|
||||||
|
|
||||||
std::vector<uint256> childHashes;
|
std::vector<uint256> childHashes;
|
||||||
for (auto&& row: childQuery) {
|
for (auto&& row: childQuery) {
|
||||||
std::string key;
|
std::string key;
|
||||||
int keyLastTakeoverHeight;
|
|
||||||
std::unique_ptr<uint256> hash;
|
std::unique_ptr<uint256> hash;
|
||||||
row >> key >> hash >> keyLastTakeoverHeight;
|
row >> key >> hash;
|
||||||
if (hash == nullptr) hash = std::make_unique<uint256>();
|
if (hash == nullptr) hash = std::make_unique<uint256>();
|
||||||
if (hash->IsNull()) {
|
if (hash->IsNull()) {
|
||||||
*hash = recursiveComputeMerkleHash(key, keyLastTakeoverHeight, checkOnly);
|
*hash = recursiveComputeMerkleHash(key, checkOnly);
|
||||||
}
|
}
|
||||||
childHashes.push_back(*hash);
|
childHashes.push_back(*hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto claimQuery = base->_db << "SELECT c.txID, c.txN, c.validHeight, c.amount + "
|
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"
|
"SUM(SELECT s.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
|
||||||
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? "
|
"AND s.validHeight < ? AND s.expirationHeight >= ?) as effectiveAmount"
|
||||||
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN" << nNextHeight << name << nNextHeight;
|
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? AND c.expirationHeight >= ? "
|
||||||
|
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN" << nNextHeight << nNextHeight << name << nNextHeight << nNextHeight;
|
||||||
|
|
||||||
std::vector<uint256> claimHashes;
|
std::vector<uint256> claimHashes;
|
||||||
for (auto&& row: claimQuery) {
|
for (auto&& row: claimQuery) {
|
||||||
COutPoint p;
|
COutPoint p;
|
||||||
row >> p.hash >> p.n;
|
int validHeight;
|
||||||
auto claimHash = getValueHash(p, lastTakeoverHeight);
|
row >> p.hash >> p.n >> validHeight;
|
||||||
|
auto claimHash = getValueHash(p, validHeight);
|
||||||
claimHashes.push_back(claimHash);
|
claimHashes.push_back(claimHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,13 +308,13 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
|
||||||
// cache the parent nodes
|
// cache the parent nodes
|
||||||
getMerkleHash();
|
getMerkleHash();
|
||||||
proof = CClaimTrieProof();
|
proof = CClaimTrieProof();
|
||||||
auto nodeQuery = base->_db << "SELECT name, lastTakeoverHeight FROM nodes WHERE "
|
auto nodeQuery = base->_db << "SELECT name FROM nodes WHERE "
|
||||||
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
||||||
"SELECT SUBSTR(p, 0, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
"SELECT SUBSTR(p, 1, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
||||||
"ORDER BY LENGTH(name)" << name;
|
"ORDER BY LENGTH(name)" << name;
|
||||||
for (auto&& row: nodeQuery) {
|
for (auto&& row: nodeQuery) {
|
||||||
std::string key; int lastTakeover;
|
std::string key;;
|
||||||
row >> key >> lastTakeover;
|
row >> key;
|
||||||
std::vector<uint256> childHashes;
|
std::vector<uint256> childHashes;
|
||||||
uint32_t nextCurrentIdx = 0;
|
uint32_t nextCurrentIdx = 0;
|
||||||
auto childQuery = base->_db << "SELECT name, hash FROM nodes WHERE parent = ?" << key;
|
auto childQuery = base->_db << "SELECT name, hash FROM nodes WHERE parent = ?" << key;
|
||||||
|
@ -332,7 +333,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
|
||||||
COutPoint finalOutPoint;
|
COutPoint finalOutPoint;
|
||||||
for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) {
|
for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) {
|
||||||
auto& child = cns.claimsNsupports[i].claim;
|
auto& child = cns.claimsNsupports[i].claim;
|
||||||
claimHashes.push_back(getValueHash(child.outPoint, lastTakeover));
|
claimHashes.push_back(getValueHash(child.outPoint, child.nValidAtHeight));
|
||||||
if (child.claimId == finalClaim) {
|
if (child.claimId == finalClaim) {
|
||||||
finalClaimIdx = i;
|
finalClaimIdx = i;
|
||||||
finalOutPoint = child.outPoint;
|
finalOutPoint = child.outPoint;
|
||||||
|
@ -344,7 +345,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
|
||||||
// else it will be hash(x, claims)
|
// else it will be hash(x, claims)
|
||||||
if (key == name) {
|
if (key == name) {
|
||||||
proof.outPoint = finalOutPoint;
|
proof.outPoint = finalOutPoint;
|
||||||
proof.nHeightOfLastTakeover = lastTakeover;
|
proof.nHeightOfLastTakeover = cns.nLastTakeoverHeight;
|
||||||
proof.hasValue = true;
|
proof.hasValue = true;
|
||||||
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
|
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
|
||||||
proof.pairs.emplace_back(true, hash);
|
proof.pairs.emplace_back(true, hash);
|
||||||
|
@ -369,9 +370,9 @@ void CClaimTrieCacheHashFork::initializeIncrement()
|
||||||
base->_db << "UPDATE nodes SET hash = NULL";
|
base->_db << "UPDATE nodes SET hash = NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClaimTrieCacheHashFork::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
bool CClaimTrieCacheHashFork::finalizeDecrement()
|
||||||
{
|
{
|
||||||
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverHeightUndo);
|
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement();
|
||||||
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
|
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
|
||||||
base->_db << "UPDATE nodes SET hash = NULL";
|
base->_db << "UPDATE nodes SET hash = NULL";
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -59,7 +59,6 @@ void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight)
|
||||||
claimQueueRowType dummyExpireUndo;
|
claimQueueRowType dummyExpireUndo;
|
||||||
insertUndoType dummyInsertSupportUndo;
|
insertUndoType dummyInsertSupportUndo;
|
||||||
supportQueueRowType dummyExpireSupportUndo;
|
supportQueueRowType dummyExpireSupportUndo;
|
||||||
std::vector<std::pair<std::string, int> > dummyTakeoverHeightUndo;
|
|
||||||
|
|
||||||
CUpdateCacheCallbacks callbacks = {
|
CUpdateCacheCallbacks callbacks = {
|
||||||
.findScriptKey = [&pblock](const COutPoint& point) {
|
.findScriptKey = [&pblock](const COutPoint& point) {
|
||||||
|
@ -79,7 +78,7 @@ void blockToCache(const CBlock* pblock, CClaimTrieCache& trieCache, int nHeight)
|
||||||
if (!tx->IsCoinBase())
|
if (!tx->IsCoinBase())
|
||||||
UpdateCache(*tx, trieCache, view, nHeight, callbacks);
|
UpdateCache(*tx, trieCache, view, nHeight, callbacks);
|
||||||
|
|
||||||
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo);
|
trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAssembler::Options::Options() {
|
BlockAssembler::Options::Options() {
|
||||||
|
|
|
@ -17,7 +17,7 @@ CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stop
|
||||||
|
|
||||||
CScheduler::~CScheduler()
|
CScheduler::~CScheduler()
|
||||||
{
|
{
|
||||||
assert(nThreadsServicingQueue == 0);
|
assert(!AreThreadsServicingQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,24 +7,25 @@
|
||||||
|
|
||||||
namespace sqlite {
|
namespace sqlite {
|
||||||
|
|
||||||
class sqlite_exception: public std::runtime_error {
|
class sqlite_exception: public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
sqlite_exception(const char* msg, str_ref sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
|
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) {}
|
sqlite_exception(int code, str_ref sql, const char *msg = nullptr): runtime_error(msg ? msg : sqlite3_errstr(code)), code(code), sql(sql) {}
|
||||||
int get_code() const {return code & 0xFF;}
|
int get_code() const {return code & 0xFF;}
|
||||||
int get_extended_code() const {return code;}
|
int get_extended_code() const {return code;}
|
||||||
std::string get_sql() const {return sql;}
|
std::string get_sql() const {return sql;}
|
||||||
private:
|
const char *errstr() const {return code == -1 ? "Unknown error" : sqlite3_errstr(code);}
|
||||||
int code;
|
private:
|
||||||
std::string sql;
|
int code;
|
||||||
};
|
std::string sql;
|
||||||
|
};
|
||||||
|
|
||||||
namespace errors {
|
namespace errors {
|
||||||
//One more or less trivial derived error class for each SQLITE error.
|
//One more or less trivial derived error class for each SQLITE error.
|
||||||
//Note the following are not errors so have no classes:
|
//Note the following are not errors so have no classes:
|
||||||
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
|
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
|
||||||
//
|
//
|
||||||
//Note these names are exact matches to the names of the SQLITE error codes.
|
//Note these names are exact matches to the names of the SQLITE error codes.
|
||||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
||||||
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
|
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
|
||||||
derived
|
derived
|
||||||
|
@ -34,15 +35,15 @@ namespace sqlite {
|
||||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||||
|
|
||||||
//Some additional errors are here for the C++ interface
|
//Some additional errors are here for the C++ interface
|
||||||
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||||
class no_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 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 invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||||
class unknown_binding: 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 = "") {
|
static void throw_sqlite_error(const int& error_code, str_ref sql = "", const char *errmsg = nullptr) {
|
||||||
switch(error_code & 0xFF) {
|
switch(error_code & 0xFF) {
|
||||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
||||||
case SQLITE_ ## NAME: switch(error_code) { \
|
case SQLITE_ ## NAME: switch(error_code) { \
|
||||||
derived \
|
derived \
|
||||||
|
@ -51,19 +52,19 @@ namespace sqlite {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SQLITE_VERSION_NUMBER < 3010000
|
#if SQLITE_VERSION_NUMBER < 3010000
|
||||||
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
|
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
|
||||||
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
|
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
|
||||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
|
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
|
||||||
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql);
|
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql, errmsg);
|
||||||
#include "lists/error_codes.h"
|
#include "lists/error_codes.h"
|
||||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||||
default: throw sqlite_exception(error_code, sql);
|
default: throw sqlite_exception(error_code, sql, errmsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace exceptions = errors;
|
namespace exceptions = errors;
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
#ifdef __has_include
|
#ifdef __has_include
|
||||||
#if __cplusplus > 201402 && __has_include(<optional>)
|
#if __cplusplus > 201402 && __has_include(<optional>)
|
||||||
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||||
#elif __has_include(<experimental/optional>)
|
#elif __has_include(<experimental/optional>) && __apple_build_version__ < 11000000
|
||||||
#define MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
#define MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,130 +45,130 @@ namespace sqlite
|
||||||
#else
|
#else
|
||||||
namespace sqlite
|
namespace sqlite
|
||||||
{
|
{
|
||||||
typedef const std::string& str_ref;
|
typedef const std::string& str_ref;
|
||||||
typedef const std::u16string& u16str_ref;
|
typedef const std::u16string& u16str_ref;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#include <sqlite/sqlite3.h>
|
#include <sqlite/sqlite3.h>
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
|
|
||||||
namespace sqlite {
|
namespace sqlite {
|
||||||
template<class T, int Type, class = void>
|
template<class T, int Type, class = void>
|
||||||
struct has_sqlite_type : std::false_type {};
|
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>
|
template<class T>
|
||||||
struct has_sqlite_type<T&, Type> : has_sqlite_type<T, Type> {};
|
using is_sqlite_value = std::integral_constant<bool, false
|
||||||
template<class T, int Type>
|
|| has_sqlite_type<T, SQLITE_NULL>::value
|
||||||
struct has_sqlite_type<const T, Type> : has_sqlite_type<T, Type> {};
|
|| has_sqlite_type<T, SQLITE_INTEGER>::value
|
||||||
template<class T, int Type>
|
|| has_sqlite_type<T, SQLITE_FLOAT>::value
|
||||||
struct has_sqlite_type<volatile T, Type> : has_sqlite_type<T, Type> {};
|
|| has_sqlite_type<T, SQLITE_TEXT>::value
|
||||||
|
|| has_sqlite_type<T, SQLITE_BLOB>::value
|
||||||
|
>;
|
||||||
|
|
||||||
template<class T>
|
template<class T, int Type>
|
||||||
struct result_type {
|
struct has_sqlite_type<T&, Type> : has_sqlite_type<T, Type> {};
|
||||||
using type = T;
|
template<class T, int Type>
|
||||||
constexpr result_type() = default;
|
struct has_sqlite_type<const T, Type> : has_sqlite_type<T, Type> {};
|
||||||
template<class U, class = typename std::enable_if<std::is_assignable<U, T>::value>>
|
template<class T, int Type>
|
||||||
constexpr result_type(result_type<U>) { }
|
struct has_sqlite_type<volatile T, Type> : has_sqlite_type<T, Type> {};
|
||||||
};
|
|
||||||
|
|
||||||
// int
|
template<class T>
|
||||||
template<>
|
struct result_type {
|
||||||
struct has_sqlite_type<int, SQLITE_INTEGER> : std::true_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>) { }
|
||||||
|
};
|
||||||
|
|
||||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const int& val) {
|
// int
|
||||||
return sqlite3_bind_int(stmt, inx, val);
|
template<>
|
||||||
}
|
struct has_sqlite_type<int, SQLITE_INTEGER> : std::true_type {};
|
||||||
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
|
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const int& val) {
|
||||||
template<>
|
return sqlite3_bind_int(stmt, inx, val);
|
||||||
struct has_sqlite_type<sqlite_int64, SQLITE_INTEGER, void> : std::true_type {};
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
|
// sqlite_int64
|
||||||
return sqlite3_bind_int64(stmt, inx, val);
|
template<>
|
||||||
}
|
struct has_sqlite_type<sqlite_int64, SQLITE_INTEGER, void> : std::true_type {};
|
||||||
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
|
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
|
||||||
template<>
|
return sqlite3_bind_int64(stmt, inx, val);
|
||||||
struct has_sqlite_type<float, SQLITE_FLOAT, void> : std::true_type {};
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const float& val) {
|
// float
|
||||||
return sqlite3_bind_double(stmt, inx, double(val));
|
template<>
|
||||||
}
|
struct has_sqlite_type<float, SQLITE_FLOAT, void> : std::true_type {};
|
||||||
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
|
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const float& val) {
|
||||||
template<>
|
return sqlite3_bind_double(stmt, inx, double(val));
|
||||||
struct has_sqlite_type<double, SQLITE_FLOAT, void> : std::true_type {};
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const double& val) {
|
// double
|
||||||
return sqlite3_bind_double(stmt, inx, val);
|
template<>
|
||||||
}
|
struct has_sqlite_type<double, SQLITE_FLOAT, void> : std::true_type {};
|
||||||
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 */
|
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const double& val) {
|
||||||
template<>
|
return sqlite3_bind_double(stmt, inx, val);
|
||||||
struct has_sqlite_type<std::nullptr_t, SQLITE_NULL, void> : std::true_type {};
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::nullptr_t) {
|
/* for nullptr support */
|
||||||
return sqlite3_bind_null(stmt, inx);
|
template<>
|
||||||
}
|
struct has_sqlite_type<std::nullptr_t, SQLITE_NULL, void> : std::true_type {};
|
||||||
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
|
|
||||||
sqlite3_result_null(db);
|
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
|
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||||
template<>
|
template<>
|
||||||
struct has_sqlite_type<std::monostate, SQLITE_NULL, void> : std::true_type {};
|
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) {
|
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::monostate) {
|
||||||
|
@ -185,184 +185,184 @@ namespace sqlite {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// str_ref
|
// str_ref
|
||||||
template<>
|
template<>
|
||||||
struct has_sqlite_type<std::string, SQLITE3_TEXT, void> : std::true_type {};
|
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) {
|
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);
|
return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert char* to string_view to trigger op<<(..., const str_ref )
|
// 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]) {
|
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);
|
return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::string>) {
|
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() :
|
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));
|
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 >) {
|
inline std::string get_val_from_db(sqlite3_value *value, result_type<std::string >) {
|
||||||
return sqlite3_value_type(value) == SQLITE_NULL ? 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));
|
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) {
|
inline void store_result_in_db(sqlite3_context* db, str_ref val) {
|
||||||
sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT);
|
sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
// u16str_ref
|
// u16str_ref
|
||||||
template<>
|
template<>
|
||||||
struct has_sqlite_type<std::u16string, SQLITE3_TEXT, void> : std::true_type {};
|
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) {
|
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);
|
return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert char* to string_view to trigger op<<(..., const str_ref )
|
// 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]) {
|
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);
|
return sqlite3_bind_text16(stmt, inx, &STR[0], sizeof(char16_t) * (N-1), SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::u16string>) {
|
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() :
|
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));
|
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>) {
|
inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string>) {
|
||||||
return sqlite3_value_type(value) == SQLITE_NULL ? 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));
|
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) {
|
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);
|
sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other integer types
|
// Other integer types
|
||||||
template<class Integral>
|
template<class Integral>
|
||||||
struct has_sqlite_type<Integral, SQLITE_INTEGER, typename std::enable_if<std::is_integral<Integral>::value>::type> : std::true_type {};
|
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>
|
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) {
|
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));
|
return bind_col_in_db(stmt, inx, static_cast<sqlite3_int64>(val));
|
||||||
}
|
}
|
||||||
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
|
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
|
||||||
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
|
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
|
||||||
store_result_in_db(db, static_cast<sqlite3_int64>(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>
|
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>) {
|
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>());
|
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>
|
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>) {
|
inline Integral get_val_from_db(sqlite3_value *value, result_type<Integral>) {
|
||||||
return get_val_from_db(value, result_type<sqlite3_int64>());
|
return get_val_from_db(value, result_type<sqlite3_int64>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// vector<T, A>
|
// vector<T, A>
|
||||||
template<typename T, typename A>
|
template<typename T, typename A>
|
||||||
struct has_sqlite_type<std::vector<T, A>, SQLITE_BLOB, void> : std::true_type {};
|
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) {
|
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());
|
void const* buf = reinterpret_cast<void const *>(vec.data());
|
||||||
int bytes = vec.size() * sizeof(T);
|
int bytes = vec.size() * sizeof(T);
|
||||||
return sqlite3_bind_blob(stmt, inx, buf, bytes, SQLITE_STATIC);
|
return sqlite3_bind_blob(stmt, inx, buf, bytes, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
template<typename T, typename A> inline void store_result_in_db(sqlite3_context* db, const std::vector<T, A>& vec) {
|
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());
|
void const* buf = reinterpret_cast<void const *>(vec.data());
|
||||||
int bytes = vec.size() * sizeof(T);
|
int bytes = vec.size() * sizeof(T);
|
||||||
sqlite3_result_blob(db, buf, bytes, SQLITE_TRANSIENT);
|
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>>) {
|
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) {
|
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||||
T const* buf = reinterpret_cast<T const *>(sqlite3_column_blob(stmt, inx));
|
T const* buf = reinterpret_cast<T const *>(sqlite3_column_blob(stmt, inx));
|
||||||
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
|
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>>) {
|
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) {
|
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
int bytes = sqlite3_value_bytes(value);
|
int bytes = sqlite3_value_bytes(value);
|
||||||
T const* buf = reinterpret_cast<T const *>(sqlite3_value_blob(value));
|
T const* buf = reinterpret_cast<T const *>(sqlite3_value_blob(value));
|
||||||
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
|
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for unique_ptr<T> support */
|
/* for unique_ptr<T> support */
|
||||||
template<typename T, int Type>
|
template<typename T, int Type>
|
||||||
struct has_sqlite_type<std::unique_ptr<T>, Type, void> : has_sqlite_type<T, Type> {};
|
struct has_sqlite_type<std::unique_ptr<T>, Type, void> : has_sqlite_type<T, Type> {};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_sqlite_type<std::unique_ptr<T>, SQLITE_NULL, void> : std::true_type {};
|
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) {
|
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);
|
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>>) {
|
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) {
|
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_unique<T>(get_col_from_db(stmt, inx, result_type<T>()));
|
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>>) {
|
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) {
|
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_unique<T>(get_val_from_db(value, result_type<T>()));
|
return std::make_unique<T>(get_val_from_db(value, result_type<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::optional support for NULL values
|
// std::optional support for NULL values
|
||||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||||
template<class T>
|
template<class T>
|
||||||
using optional = std::experimental::optional<T>;
|
using optional = std::experimental::optional<T>;
|
||||||
#else
|
#else
|
||||||
template<class T>
|
template<class T>
|
||||||
using optional = std::optional<T>;
|
using optional = std::optional<T>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T, int Type>
|
template<typename T, int Type>
|
||||||
struct has_sqlite_type<optional<T>, Type, void> : has_sqlite_type<T, Type> {};
|
struct has_sqlite_type<optional<T>, Type, void> : has_sqlite_type<T, Type> {};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_sqlite_type<optional<T>, SQLITE_NULL, void> : std::true_type {};
|
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) {
|
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);
|
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) {
|
template <typename OptionalT> inline void store_result_in_db(sqlite3_context* db, const optional<OptionalT>& val) {
|
||||||
if(val)
|
if(val)
|
||||||
store_result_in_db(db, *val);
|
store_result_in_db(db, *val);
|
||||||
else
|
else
|
||||||
sqlite3_result_null(db);
|
sqlite3_result_null(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OptionalT> inline optional<OptionalT> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<optional<OptionalT>>) {
|
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
|
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||||
return std::experimental::nullopt;
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
return std::experimental::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
return std::experimental::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
||||||
#else
|
#else
|
||||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return std::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
return std::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
template <typename OptionalT> inline optional<OptionalT> get_val_from_db(sqlite3_value *value, result_type<optional<OptionalT>>) {
|
template <typename OptionalT> inline optional<OptionalT> get_val_from_db(sqlite3_value *value, result_type<optional<OptionalT>>) {
|
||||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||||
return std::experimental::nullopt;
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
return std::experimental::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
return std::experimental::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
||||||
#else
|
#else
|
||||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return std::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
return std::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
struct tag_trait : U { using tag = T; };
|
struct tag_trait : U { using tag = T; };
|
||||||
}
|
}
|
||||||
|
@ -415,4 +415,4 @@ namespace sqlite {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
|
@ -303,8 +303,7 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
|
||||||
CClaimTrieCacheTest cache(&trie);
|
CClaimTrieCacheTest cache(&trie);
|
||||||
|
|
||||||
insertUndoType icu, isu; claimQueueRowType ecu; supportQueueRowType esu;
|
insertUndoType icu, isu; claimQueueRowType ecu; supportQueueRowType esu;
|
||||||
std::vector<std::pair<std::string, int>> thu;
|
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
|
||||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
|
||||||
|
|
||||||
CClaimValue value;
|
CClaimValue value;
|
||||||
value.nHeight = 1;
|
value.nHeight = 1;
|
||||||
|
@ -317,9 +316,9 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
|
||||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
||||||
BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue()));
|
BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue()));
|
||||||
|
|
||||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
|
||||||
BOOST_CHECK(cache.flush());
|
BOOST_CHECK(cache.flush());
|
||||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
|
||||||
BOOST_CHECK_EQUAL(0, cache.getTotalNamesInTrie());
|
BOOST_CHECK_EQUAL(0, cache.getTotalNamesInTrie());
|
||||||
|
|
||||||
CSupportValue temp;
|
CSupportValue temp;
|
||||||
|
@ -336,7 +335,7 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
|
||||||
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value));
|
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value));
|
||||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
||||||
|
|
||||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu));
|
||||||
|
|
||||||
BOOST_CHECK(cache.getInfoForName("aa", cv));
|
BOOST_CHECK(cache.getInfoForName("aa", cv));
|
||||||
BOOST_CHECK_EQUAL(3, cv.nValidAtHeight);
|
BOOST_CHECK_EQUAL(3, cv.nValidAtHeight);
|
||||||
|
|
|
@ -227,8 +227,7 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
|
||||||
claimQueueRowType expireUndo;
|
claimQueueRowType expireUndo;
|
||||||
insertUndoType insertSupportUndo;
|
insertUndoType insertSupportUndo;
|
||||||
supportQueueRowType expireSupportUndo;
|
supportQueueRowType expireSupportUndo;
|
||||||
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
|
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
|
||||||
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
|
|
||||||
BOOST_CHECK(trieCache.shouldNormalize());
|
BOOST_CHECK(trieCache.shouldNormalize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,14 +313,13 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
|
||||||
claimQueueRowType expireUndo;
|
claimQueueRowType expireUndo;
|
||||||
insertUndoType insertSupportUndo;
|
insertUndoType insertSupportUndo;
|
||||||
supportQueueRowType expireSupportUndo;
|
supportQueueRowType expireSupportUndo;
|
||||||
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
|
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
|
||||||
BOOST_CHECK(cache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
|
|
||||||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U);
|
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 3U);
|
||||||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U);
|
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[0].supports.size() == 1U);
|
||||||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U);
|
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[1].supports.size() == 0U);
|
||||||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
|
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
|
||||||
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
|
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
|
||||||
BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo));
|
BOOST_CHECK(cache.finalizeDecrement());
|
||||||
std::string unused;
|
std::string unused;
|
||||||
BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height));
|
BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height));
|
||||||
BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height));
|
BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height));
|
||||||
|
|
|
@ -78,7 +78,6 @@ public:
|
||||||
claimQueueRowType expireUndo; // any claims that expired
|
claimQueueRowType expireUndo; // any claims that expired
|
||||||
insertUndoType insertSupportUndo; // any supports that went from the support queue to the support map
|
insertUndoType insertSupportUndo; // any supports that went from the support queue to the support map
|
||||||
supportQueueRowType expireSupportUndo; // any supports that expired
|
supportQueueRowType expireSupportUndo; // any supports that expired
|
||||||
std::vector<std::pair<std::string, int> > takeoverHeightUndo; // for any name that was taken over, the previous time that name was taken over
|
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
@ -89,7 +88,6 @@ public:
|
||||||
READWRITE(expireUndo);
|
READWRITE(expireUndo);
|
||||||
READWRITE(insertSupportUndo);
|
READWRITE(insertSupportUndo);
|
||||||
READWRITE(expireSupportUndo);
|
READWRITE(expireSupportUndo);
|
||||||
READWRITE(takeoverHeightUndo);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1559,7 +1559,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
|
||||||
|
|
||||||
// move best block pointer to prevout block
|
// move best block pointer to prevout block
|
||||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||||
assert(trieCache.finalizeDecrement(blockUndo.takeoverHeightUndo));
|
assert(trieCache.finalizeDecrement());
|
||||||
auto merkleHash = trieCache.getMerkleHash();
|
auto merkleHash = trieCache.getMerkleHash();
|
||||||
if (merkleHash != pindex->pprev->hashClaimTrie) {
|
if (merkleHash != pindex->pprev->hashClaimTrie) {
|
||||||
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
|
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
|
||||||
|
@ -2033,7 +2033,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient.
|
// TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient.
|
||||||
const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo, blockundo.takeoverHeightUndo);
|
const auto incremented = trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo);
|
||||||
assert(incremented);
|
assert(incremented);
|
||||||
|
|
||||||
if (trieCache.getMerkleHash() != block.hashClaimTrie)
|
if (trieCache.getMerkleHash() != block.hashClaimTrie)
|
||||||
|
|
Loading…
Reference in a new issue