Use fully static linkage #364
13 changed files with 104 additions and 50 deletions
|
@ -56,8 +56,8 @@ public:
|
|||
{
|
||||
static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
|
||||
|
||||
pn[0] = (unsigned int)b;
|
||||
pn[1] = (unsigned int)(b >> 32);
|
||||
pn[0] = uint32_t(b);
|
||||
pn[1] = uint32_t(b >> 32U);
|
||||
for (int i = 2; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
}
|
||||
|
|
|
@ -72,12 +72,18 @@ void CBaseBlob<BITS>::SetNull()
|
|||
}
|
||||
|
||||
template<uint32_t BITS>
|
||||
std::string CBaseBlob<BITS>::GetHex() const
|
||||
std::string CBaseBlob<BITS>::GetHex(bool reverse) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex;
|
||||
for (auto it = data.rbegin(); it != data.rend(); ++it)
|
||||
ss << std::setw(2) << std::setfill('0') << uint32_t(*it);
|
||||
if (reverse) {
|
||||
for (auto it = data.rbegin(); it != data.rend(); ++it)
|
||||
ss << std::setw(2) << std::setfill('0') << uint32_t(*it);
|
||||
}
|
||||
else {
|
||||
for (auto it = data.begin(); it != data.end(); ++it)
|
||||
ss << std::setw(2) << std::setfill('0') << uint32_t(*it);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
bool IsNull() const;
|
||||
void SetNull();
|
||||
|
||||
std::string GetHex() const;
|
||||
std::string GetHex(bool reverse=true) const;
|
||||
void SetHex(const char* psz);
|
||||
void SetHex(const std::string& str);
|
||||
|
||||
|
|
|
@ -49,10 +49,22 @@ namespace sqlite
|
|||
|
||||
inline uint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint256>) {
|
||||
uint256 ret;
|
||||
|
||||
// I think we need this, but I lost my specific test case:
|
||||
// auto type = sqlite3_column_type(stmt, inx);
|
||||
// if (type == SQLITE_NULL)
|
||||
// return ret;
|
||||
//
|
||||
// if (type == SQLITE_INTEGER) {
|
||||
// auto integer = sqlite3_column_int64(stmt, inx);
|
||||
// return uint256(integer);
|
||||
// }
|
||||
// assert(type == SQLITE_BLOB);
|
||||
|
||||
auto ptr = sqlite3_column_blob(stmt, inx);
|
||||
if (!ptr) return ret;
|
||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||
assert(bytes > 0 && bytes <= int(ret.size()));
|
||||
assert(bytes <= ret.size());
|
||||
std::memcpy(ret.begin(), ptr, bytes);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -77,34 +77,19 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height,
|
|||
"parent BLOB REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, "
|
||||
"hash BLOB)";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS node_hash_len_name ON node (hash, LENGTH(name) DESC)";
|
||||
// db << "CREATE UNIQUE INDEX IF NOT EXISTS node_parent_name ON node (parent, name)"; // no apparent gain
|
||||
db << "CREATE INDEX IF NOT EXISTS node_parent ON node (parent)";
|
||||
|
||||
db << "CREATE TABLE IF NOT EXISTS takeover (name BLOB NOT NULL, height INTEGER NOT NULL, "
|
||||
"claimID BLOB, PRIMARY KEY(name, height DESC));";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS takeover_height ON takeover (height)";
|
||||
|
||||
db << "CREATE TABLE IF NOT EXISTS claim (claimID BLOB NOT NULL PRIMARY KEY, name BLOB NOT NULL, "
|
||||
"nodeName BLOB NOT NULL REFERENCES node(name) DEFERRABLE INITIALLY DEFERRED, "
|
||||
"txID BLOB NOT NULL, txN INTEGER NOT NULL, originalHeight INTEGER NOT NULL, updateHeight INTEGER NOT NULL, "
|
||||
"validHeight INTEGER NOT NULL, activationHeight INTEGER NOT NULL, "
|
||||
"expirationHeight INTEGER NOT NULL, amount INTEGER NOT NULL);";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_activationHeight ON claim (activationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_expirationHeight ON claim (expirationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_nodeName ON claim (nodeName)";
|
||||
|
||||
db << "CREATE TABLE IF NOT EXISTS support (txID BLOB NOT NULL, txN INTEGER NOT NULL, "
|
||||
"supportedClaimID BLOB NOT NULL, name BLOB NOT NULL, nodeName BLOB NOT NULL, "
|
||||
"blockHeight INTEGER NOT NULL, validHeight INTEGER NOT NULL, activationHeight INTEGER NOT NULL, "
|
||||
"expirationHeight INTEGER NOT NULL, amount INTEGER NOT NULL, PRIMARY KEY(txID, txN));";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS support_supportedClaimID ON support (supportedClaimID)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_activationHeight ON support (activationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_expirationHeight ON support (expirationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_nodeName ON support (nodeName)";
|
||||
db << "CREATE TABLE IF NOT EXISTS takeover (name BLOB NOT NULL, height INTEGER NOT NULL, "
|
||||
"claimID BLOB, PRIMARY KEY(name, height DESC));";
|
||||
|
||||
if (fWipe) {
|
||||
db << "DELETE FROM node";
|
||||
|
@ -113,6 +98,21 @@ CClaimTrie::CClaimTrie(std::size_t cacheBytes, bool fWipe, int height,
|
|||
db << "DELETE FROM takeover";
|
||||
}
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS node_hash_len_name ON node (hash, LENGTH(name) DESC)";
|
||||
// db << "CREATE UNIQUE INDEX IF NOT EXISTS node_parent_name ON node (parent, name)"; // no apparent gain
|
||||
db << "CREATE INDEX IF NOT EXISTS node_parent ON node (parent)";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS takeover_height ON takeover (height)";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_activationHeight ON claim (activationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_expirationHeight ON claim (expirationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS claim_nodeName ON claim (nodeName)";
|
||||
|
||||
db << "CREATE INDEX IF NOT EXISTS support_supportedClaimID ON support (supportedClaimID)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_activationHeight ON support (activationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_expirationHeight ON support (expirationHeight)";
|
||||
db << "CREATE INDEX IF NOT EXISTS support_nodeName ON support (nodeName)";
|
||||
|
||||
db << "INSERT OR IGNORE INTO node(name, hash) VALUES(x'', ?)" << one; // ensure that we always have our root node
|
||||
}
|
||||
|
||||
|
@ -457,9 +457,7 @@ bool CClaimTrieCacheBase::validateDb(int height, const uint256& rootHash)
|
|||
{
|
||||
base->nNextHeight = nNextHeight = height + 1;
|
||||
|
||||
logPrint << "Checking claim trie consistency... " << Clog::flush;
|
||||
if (checkConsistency()) {
|
||||
logPrint << "consistent" << Clog::endl;
|
||||
if (rootHash != getMerkleHash()) {
|
||||
logPrint << "CClaimTrieCacheBase::" << __func__ << "(): the block's root claim hash doesn't match the persisted claim root hash." << Clog::endl;
|
||||
return false;
|
||||
|
@ -470,7 +468,6 @@ bool CClaimTrieCacheBase::validateDb(int height, const uint256& rootHash)
|
|||
|
||||
return true;
|
||||
}
|
||||
logPrint << "inconsistent!" << Clog::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -650,7 +647,6 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
|
|||
|
||||
*it >> nodeName >> originalHeight >> validHeight;
|
||||
}
|
||||
|
||||
ensureTransacting();
|
||||
|
||||
db << "DELETE FROM claim WHERE claimID = ? AND txID = ? AND txN = ?"
|
||||
|
@ -683,13 +679,18 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
|
|||
|
||||
bool CClaimTrieCacheBase::removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight)
|
||||
{
|
||||
{
|
||||
auto query = db << "SELECT nodeName, activationHeight FROM support "
|
||||
"WHERE txID = ? AND txN = ? AND expirationHeight >= ?"
|
||||
<< outPoint.hash << outPoint.n << nNextHeight;
|
||||
auto it = query.begin();
|
||||
if (it == query.end())
|
||||
return false;
|
||||
|
||||
*it >> nodeName >> validHeight;
|
||||
}
|
||||
ensureTransacting();
|
||||
|
||||
auto query = db << "SELECT nodeName, activationHeight FROM support WHERE txID = ? AND txN = ? AND expirationHeight >= ?"
|
||||
<< outPoint.hash << outPoint.n << nNextHeight;
|
||||
auto it = query.begin();
|
||||
if (it == query.end()) return false;
|
||||
*it >> nodeName >> validHeight;
|
||||
db << "DELETE FROM support WHERE txID = ? AND txN = ?" << outPoint.hash << outPoint.n;
|
||||
if (!db.rows_modified())
|
||||
return false;
|
||||
|
@ -925,7 +926,7 @@ std::vector<uint160> CClaimTrieCacheBase::getActivatedClaims(int height) {
|
|||
}
|
||||
std::vector<uint160> CClaimTrieCacheBase::getClaimsWithActivatedSupports(int height) {
|
||||
std::vector<uint160> ret;
|
||||
auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE activationHeight = ?1 AND updateHeight < ?1" << height;
|
||||
auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE activationHeight = ?1 AND blockHeight < ?1" << height;
|
||||
for (auto&& row: query) {
|
||||
ret.emplace_back();
|
||||
row >> ret.back();
|
||||
|
@ -943,7 +944,7 @@ std::vector<uint160> CClaimTrieCacheBase::getExpiredClaims(int height) {
|
|||
}
|
||||
std::vector<uint160> CClaimTrieCacheBase::getClaimsWithExpiredSupports(int height) {
|
||||
std::vector<uint160> ret;
|
||||
auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE expirationHeight = ?1 AND updateHeight < ?1" << height;
|
||||
auto query = db << "SELECT DISTINCT supportedClaimID FROM support WHERE expirationHeight = ?1 AND blockHeight < ?1" << height;
|
||||
for (auto&& row: query) {
|
||||
ret.emplace_back();
|
||||
row >> ret.back();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include <uints.h>
|
||||
#include <cstring>
|
||||
|
||||
uint160::uint160(const std::vector<uint8_t>& vec) : CBaseBlob<160>(vec)
|
||||
{
|
||||
|
@ -9,6 +10,10 @@ uint256::uint256(const std::vector<uint8_t>& vec) : CBaseBlob<256>(vec)
|
|||
{
|
||||
}
|
||||
|
||||
uint256::uint256(int64_t value) : CBaseBlob<256>() {
|
||||
std::memcpy(this->begin(), &value, sizeof(value)); // TODO: fix the endianness here
|
||||
}
|
||||
|
||||
uint160 uint160S(const char* str)
|
||||
{
|
||||
uint160 s;
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
uint256() = default;
|
||||
|
||||
explicit uint256(const std::vector<uint8_t>& vec);
|
||||
explicit uint256(int64_t value);
|
||||
|
||||
uint256(uint256&&) = default;
|
||||
uint256& operator=(uint256&&) = default;
|
||||
|
|
|
@ -1543,8 +1543,9 @@ bool AppInitMain()
|
|||
}
|
||||
|
||||
auto tip = chainActive.Tip();
|
||||
LogPrintf("Checking existing claim trie consistency...\n");
|
||||
if (tip && !CClaimTrieCache(pclaimTrie).validateDb(tip->nHeight, tip->hashClaimTrie)) {
|
||||
strLoadError = _("Error validating the claim trie from disk");
|
||||
strLoadError = _("Error validating the stored claim trie");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_
|
|||
|
||||
bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &name, CClaimValue &value)
|
||||
{
|
||||
auto query = db << "SELECT nodeName, claimID, txID, txN, amount, validHeight, blockHeight "
|
||||
auto query = db << "SELECT nodeName, claimID, txID, txN, amount, validHeight, updateHeight "
|
||||
"FROM claim WHERE claimID = ?" << claimId;
|
||||
auto hit = false;
|
||||
for (auto&& row: query) {
|
||||
|
|
|
@ -280,4 +280,20 @@ BOOST_AUTO_TEST_CASE( operator_with_self )
|
|||
BOOST_CHECK(v == UintToArith256(uint256S("0")));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( bit64_all_ways )
|
||||
{
|
||||
std::vector<int64_t> tests = { 0, 1, -1, 42, 1LL << 33U, std::numeric_limits<int64_t>::max(),
|
||||
std::numeric_limits<int64_t>::lowest() };
|
||||
|
||||
for (auto test: tests) {
|
||||
auto a = uint256(test);
|
||||
auto b = arith_uint256(uint64_t(test));
|
||||
auto c = ArithToUint256(b);
|
||||
auto d = UintToArith256(a);
|
||||
BOOST_CHECK(a == c);
|
||||
BOOST_CHECK(b == d);
|
||||
BOOST_CHECK_EQUAL(a.GetHex(false), c.GetHex(false));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
30
src/txdb.cpp
30
src/txdb.cpp
|
@ -53,7 +53,7 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe)
|
|||
|
||||
bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
auto query = db << "SELECT isCoinbase, blockHeight, amount, script FROM unspent "
|
||||
"WHERE txID = ? and txN = ?" << outpoint.hash << outpoint.n;
|
||||
"WHERE txID = ? AND txN = ?" << outpoint.hash << outpoint.n;
|
||||
for (auto&& row: query) {
|
||||
uint32_t coinbase = 0, height = 0;
|
||||
row >> coinbase >> height >> coin.out.nValue >> coin.out.scriptPubKey;
|
||||
|
@ -66,10 +66,8 @@ bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
|||
|
||||
bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
|
||||
auto query = db << "SELECT 1 FROM unspent "
|
||||
"WHERE txID = ? and txN = ?" << outpoint.hash << outpoint.n;
|
||||
for (auto&& row: query)
|
||||
return true;
|
||||
return false;
|
||||
"WHERE txID = ? AND txN = ?" << outpoint.hash << outpoint.n;
|
||||
return query.begin() != query.end();
|
||||
}
|
||||
|
||||
uint256 CCoinsViewDB::GetBestBlock() const {
|
||||
|
@ -113,20 +111,26 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
|
|||
|
||||
db << "BEGIN";
|
||||
db << "INSERT OR REPLACE INTO marker VALUES('head_block', ?)" << hashBlock;
|
||||
|
||||
auto dbd = db << "DELETE FROM unspent WHERE txID = ? AND txN = ?";
|
||||
auto dbi = db << "INSERT OR REPLACE INTO unspent VALUES(?,?,?,?,?,?,?)";
|
||||
for (auto it = mapCoins.begin(); it != mapCoins.end();) {
|
||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
||||
if (it->second.coin.IsSpent()) {
|
||||
// at present the "IsSpent" flag is used for both "spent" and "block going backwards"
|
||||
db << "DELETE FROM unspent WHERE txID = ? AND txN = ?" << it->first.hash << it->first.n;
|
||||
dbd << it->first.hash << it->first.n;
|
||||
dbd++;
|
||||
}
|
||||
else {
|
||||
CTxDestination address;
|
||||
std::string destination;
|
||||
if (ExtractDestination(it->second.coin.out.scriptPubKey, address))
|
||||
destination = EncodeDestination(address);
|
||||
db << "INSERT OR REPLACE INTO unspent VALUES(?,?,?,?,?,?,?)" << it->first.hash << it->first.n
|
||||
<< it->second.coin.fCoinBase << it->second.coin.nHeight
|
||||
<< it->second.coin.out.nValue << it->second.coin.out.scriptPubKey << destination;
|
||||
uint32_t isCoinBase = it->second.coin.fCoinBase; // bit-field
|
||||
uint32_t coinHeight = it->second.coin.nHeight; // bit-field
|
||||
dbi << it->first.hash << it->first.n << isCoinBase << coinHeight
|
||||
<< it->second.coin.out.nValue << it->second.coin.out.scriptPubKey << destination;
|
||||
dbi++;
|
||||
}
|
||||
changed++;
|
||||
}
|
||||
|
@ -141,6 +145,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
|
|||
}
|
||||
}
|
||||
}
|
||||
dbd.used(true);
|
||||
dbi.used(true);
|
||||
db << "INSERT OR REPLACE INTO marker VALUES('best_block', ?)" << hashBlock;
|
||||
db << "DELETE FROM marker WHERE name = 'head_block'";
|
||||
|
||||
|
@ -201,9 +207,6 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe)
|
|||
"nonce INTEGER NOT NULL "
|
||||
")";
|
||||
|
||||
db << "CREATE UNIQUE INDEX IF NOT EXISTS block_info_height ON block_info (height)";
|
||||
db << "CREATE UNIQUE INDEX IF NOT EXISTS block_file_data_pos ON block_info (file, dataPos)";
|
||||
|
||||
db << "CREATE TABLE IF NOT EXISTS tx_to_block ("
|
||||
"txID BLOB NOT NULL PRIMARY KEY, "
|
||||
"file INTEGER NOT NULL, "
|
||||
|
@ -220,6 +223,9 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe)
|
|||
db << "DELETE FROM tx_to_block";
|
||||
db << "DELETE FROM flag";
|
||||
}
|
||||
|
||||
// not unique because we actually want to store forks:
|
||||
db << "CREATE INDEX IF NOT EXISTS block_info_height ON block_info (height)";
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
|
||||
|
|
|
@ -2493,6 +2493,12 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
|
|||
assert(flushed);
|
||||
flushed = trieCache.flush();
|
||||
assert(flushed);
|
||||
|
||||
// for verifying that rollback code works:
|
||||
// auto result = DisconnectBlock(blockConnecting, pindexNew, view, trieCache);
|
||||
// assert(result == DisconnectResult::DISCONNECT_OK);
|
||||
// assert(trieCache.getMerkleHash() == pindexNew->pprev->hashClaimTrie);
|
||||
// LogPrintf("Verified %d!\n", pindexNew->nHeight);
|
||||
}
|
||||
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
|
||||
LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
|
||||
|
|
|
@ -102,7 +102,7 @@ static const int MAX_BLOCKTXN_DEPTH = 10;
|
|||
* want to make this a per-peer adaptive value at some point. */
|
||||
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
|
||||
/** Time to wait (in seconds) between writing blocks/block index to disk. */
|
||||
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
|
||||
static const unsigned int DATABASE_WRITE_INTERVAL = 15 * 60;
|
||||
/** Time to wait (in seconds) between flushing chainstate to disk. */
|
||||
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
|
||||
/** Maximum length of reject messages. */
|
||||
|
|
Loading…
Reference in a new issue