reintroduce hash table
This commit is contained in:
parent
d6e230dcd2
commit
87dfdabf94
15 changed files with 2413 additions and 117 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -137,5 +137,8 @@ compile_commands\.json
|
||||||
|
|
||||||
osx_volname
|
osx_volname
|
||||||
dist/
|
dist/
|
||||||
|
conftest.dir/
|
||||||
|
|
||||||
|
confdefs.h
|
||||||
*.background.tiff
|
*.background.tiff
|
||||||
**/compiler*\.d
|
**/compiler*\.d
|
|
@ -174,6 +174,7 @@ BITCOIN_CORE_H = \
|
||||||
policy/settings.h \
|
policy/settings.h \
|
||||||
pow.h \
|
pow.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
|
primitives/robin_hood.h \
|
||||||
psbt.h \
|
psbt.h \
|
||||||
random.h \
|
random.h \
|
||||||
reverse_iterator.h \
|
reverse_iterator.h \
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
|
|
||||||
/** Template base class for fixed-sized opaque blobs. */
|
/** Template base class for fixed-sized opaque blobs. */
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
CBaseBlob<BITS>::CBaseBlob()
|
CBaseBlob<BITS>::CBaseBlob() noexcept : data{}
|
||||||
{
|
{
|
||||||
SetNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
|
@ -22,16 +21,15 @@ CBaseBlob<BITS>::CBaseBlob(const std::vector<uint8_t>& vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
CBaseBlob<BITS>::CBaseBlob(const CBaseBlob& o)
|
CBaseBlob<BITS>::CBaseBlob(const CBaseBlob& o) noexcept
|
||||||
{
|
{
|
||||||
*this = o;
|
*this = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
CBaseBlob<BITS>& CBaseBlob<BITS>::operator=(const CBaseBlob& o)
|
CBaseBlob<BITS>& CBaseBlob<BITS>::operator=(const CBaseBlob& o) noexcept
|
||||||
{
|
{
|
||||||
if (this != &o)
|
data = o.data;
|
||||||
std::copy(o.begin(), o.end(), begin());
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +54,7 @@ bool CBaseBlob<BITS>::operator==(const CBaseBlob& b) const
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
bool CBaseBlob<BITS>::operator!=(const CBaseBlob& b) const
|
bool CBaseBlob<BITS>::operator!=(const CBaseBlob& b) const
|
||||||
{
|
{
|
||||||
return !(*this == b);
|
return Compare(b) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint32_t BITS>
|
template<uint32_t BITS>
|
||||||
|
|
|
@ -12,15 +12,15 @@ class CBaseBlob
|
||||||
{
|
{
|
||||||
std::array<uint8_t, BITS / 8> data;
|
std::array<uint8_t, BITS / 8> data;
|
||||||
public:
|
public:
|
||||||
CBaseBlob();
|
CBaseBlob() noexcept;
|
||||||
|
|
||||||
explicit CBaseBlob(const std::vector<uint8_t>& vec);
|
explicit CBaseBlob(const std::vector<uint8_t>& vec);
|
||||||
|
|
||||||
CBaseBlob(CBaseBlob&&) = default;
|
CBaseBlob(CBaseBlob&&) = default;
|
||||||
CBaseBlob& operator=(CBaseBlob&&) = default;
|
CBaseBlob& operator=(CBaseBlob&&) = default;
|
||||||
|
|
||||||
CBaseBlob(const CBaseBlob& o);
|
CBaseBlob(const CBaseBlob& o) noexcept;
|
||||||
CBaseBlob& operator=(const CBaseBlob& o);
|
CBaseBlob& operator=(const CBaseBlob& o) noexcept;
|
||||||
|
|
||||||
int Compare(const CBaseBlob& b) const;
|
int Compare(const CBaseBlob& b) const;
|
||||||
bool operator<(const CBaseBlob& b) const;
|
bool operator<(const CBaseBlob& b) const;
|
||||||
|
|
|
@ -105,14 +105,15 @@ namespace sqlite
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int sync(database& db, std::size_t attempts = 200)
|
inline int sync(database& db, std::size_t attempts = 20)
|
||||||
{
|
{
|
||||||
int code = SQLITE_OK;
|
int code = SQLITE_OK;
|
||||||
for (auto i = 0u; i < attempts; ++i) {
|
for (auto i = 0u; i < attempts; ++i) {
|
||||||
code = sqlite3_wal_checkpoint_v2(db.connection().get(), nullptr, SQLITE_CHECKPOINT_FULL, nullptr, nullptr);
|
code = sqlite3_wal_checkpoint_v2(db.connection().get(), nullptr, SQLITE_CHECKPOINT_FULL, nullptr, nullptr);
|
||||||
if (code != SQLITE_OK) {
|
if (code != SQLITE_OK) {
|
||||||
|
sqlite3_wal_checkpoint_v2(db.connection().get(), nullptr, SQLITE_CHECKPOINT_PASSIVE, nullptr, nullptr);
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(200ms);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <blob.h>
|
#include <blob.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <primitives/robin_hood.h>
|
||||||
|
|
||||||
class uint160 : public CBaseBlob<160>
|
class uint160 : public CBaseBlob<160>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -40,4 +42,26 @@ uint160 uint160S(const std::string& s);
|
||||||
uint256 uint256S(const char* str);
|
uint256 uint256S(const char* str);
|
||||||
uint256 uint256S(const std::string& s);
|
uint256 uint256S(const std::string& s);
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<uint160>
|
||||||
|
{
|
||||||
|
size_t operator()(const uint160& k) const
|
||||||
|
{
|
||||||
|
return robin_hood::hash_bytes(k.begin(), k.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<uint256>
|
||||||
|
{
|
||||||
|
size_t operator()(const uint256& k) const
|
||||||
|
{
|
||||||
|
return robin_hood::hash_bytes(k.begin(), k.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // CLAIMTRIE_UINTS_H
|
#endif // CLAIMTRIE_UINTS_H
|
||||||
|
|
2198
src/primitives/robin_hood.h
Normal file
2198
src/primitives/robin_hood.h
Normal file
File diff suppressed because it is too large
Load diff
11
src/pubkey.h
11
src/pubkey.h
|
@ -36,6 +36,17 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<CKeyID>
|
||||||
|
{
|
||||||
|
size_t operator()(const CKeyID& k) const
|
||||||
|
{
|
||||||
|
return robin_hood::hash_bytes(k.begin(), k.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
typedef uint256 ChainCode;
|
typedef uint256 ChainCode;
|
||||||
|
|
||||||
/** An encapsulated public key. */
|
/** An encapsulated public key. */
|
||||||
|
|
|
@ -27,6 +27,17 @@ public:
|
||||||
CScriptID(const uint160& in) : uint160(in) {}
|
CScriptID(const uint160& in) : uint160(in) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<CScriptID>
|
||||||
|
{
|
||||||
|
size_t operator()(const CScriptID& k) const
|
||||||
|
{
|
||||||
|
return robin_hood::hash_bytes(k.begin(), k.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
|
* Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
|
||||||
* +2 for the pushdata opcodes.
|
* +2 for the pushdata opcodes.
|
||||||
|
|
|
@ -142,7 +142,7 @@ bool CCoinsViewDB::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBloc
|
||||||
code = sqlite::sync(db);
|
code = sqlite::sync(db);
|
||||||
if (code != SQLITE_OK) {
|
if (code != SQLITE_OK) {
|
||||||
LogPrintf("%s: Error syncing coin database. SQLite error: %d\n", __func__, code);
|
LogPrintf("%s: Error syncing coin database. SQLite error: %d\n", __func__, code);
|
||||||
return false;
|
// don't return false as it may happen if someone else is reading our DB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -326,7 +326,7 @@ bool CBlockTreeDB::BatchWrite(const std::vector<std::pair<int, const CBlockFileI
|
||||||
code = sqlite::sync(db);
|
code = sqlite::sync(db);
|
||||||
if (code != SQLITE_OK) {
|
if (code != SQLITE_OK) {
|
||||||
LogPrintf("%s: Error syncing block database. SQLite error: %d\n", __func__, code);
|
LogPrintf("%s: Error syncing block database. SQLite error: %d\n", __func__, code);
|
||||||
return false;
|
// don't return false here as this may happen if someone else is reading our DB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -83,19 +83,29 @@ bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t CBlockMapHasher::operator()(const uint256& hash) const
|
||||||
|
{
|
||||||
|
return robin_hood::hash_bytes(hash.begin(), hash.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t CBlockMapHasher::operator()(const CBlockIndex* block) const
|
||||||
|
{
|
||||||
|
return (*this)(block->hash);
|
||||||
|
}
|
||||||
|
|
||||||
bool CBlockIndexHashComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
|
bool CBlockIndexHashComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
|
||||||
{
|
{
|
||||||
return pa->hash < pb->hash;
|
return pa == pb || pa->hash == pb->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlockIndexHashComparator::operator()(const CBlockIndex* pa, const uint256& hash) const
|
bool CBlockIndexHashComparator::operator()(const CBlockIndex* pa, const uint256& hash) const
|
||||||
{
|
{
|
||||||
return pa->hash < hash;
|
return pa->hash == hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlockIndexHashComparator::operator()(const uint256& hash, const CBlockIndex* pa) const
|
bool CBlockIndexHashComparator::operator()(const uint256& hash, const CBlockIndex* pa) const
|
||||||
{
|
{
|
||||||
return hash < pa->hash;
|
return (*this)(pa, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -2514,7 +2524,7 @@ bool CChainState::FlushStateToDisk(
|
||||||
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX);
|
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX);
|
||||||
}
|
}
|
||||||
if (syncToDisk && !::Claimtrie().SyncToDisk())
|
if (syncToDisk && !::Claimtrie().SyncToDisk())
|
||||||
return state.Error("Failed to write to claim trie database");
|
LogPrintf("Failed to sync claim trie database to disk");
|
||||||
// Flush the chainstate (which may refer to block index entries).
|
// Flush the chainstate (which may refer to block index entries).
|
||||||
if (!CoinsTip().Flush(syncToDisk))
|
if (!CoinsTip().Flush(syncToDisk))
|
||||||
return AbortNode(state, "Failed to write to coin database");
|
return AbortNode(state, "Failed to write to coin database");
|
||||||
|
@ -3285,7 +3295,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
|
||||||
while (it != m_blockman.m_block_index.end()) {
|
while (it != m_blockman.m_block_index.end()) {
|
||||||
if ((*it)->IsValid(BLOCK_VALID_TRANSACTIONS) && (*it)->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(*it, m_chain.Tip()))
|
if ((*it)->IsValid(BLOCK_VALID_TRANSACTIONS) && (*it)->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(*it, m_chain.Tip()))
|
||||||
setBlockIndexCandidates.insert(*it);
|
setBlockIndexCandidates.insert(*it);
|
||||||
it++;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidChainFound(to_mark_failed);
|
InvalidChainFound(to_mark_failed);
|
||||||
|
@ -3322,7 +3332,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
|
||||||
}
|
}
|
||||||
m_blockman.m_failed_blocks.erase(*it);
|
m_blockman.m_failed_blocks.erase(*it);
|
||||||
}
|
}
|
||||||
it++;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the invalidity flag from all ancestors too.
|
// Remove the invalidity flag from all ancestors too.
|
||||||
|
@ -4814,7 +4824,8 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
|
||||||
// m_blockman.m_block_index. Note that we can't use m_chain here, since it is
|
// m_blockman.m_block_index. Note that we can't use m_chain here, since it is
|
||||||
// set based on the coins db, not the block index db, which is the only
|
// set based on the coins db, not the block index db, which is the only
|
||||||
// thing loaded at this point.
|
// thing loaded at this point.
|
||||||
if (m_blockman.m_block_index.count(chainparams.GenesisBlock().GetHash()))
|
auto it = m_blockman.m_block_index.find(chainparams.GenesisBlock().GetHash());
|
||||||
|
if (it != m_blockman.m_block_index.end())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -5329,7 +5340,7 @@ public:
|
||||||
~CMainCleanup() {
|
~CMainCleanup() {
|
||||||
// block headers
|
// block headers
|
||||||
auto it1 = g_blockman.m_block_index.begin();
|
auto it1 = g_blockman.m_block_index.begin();
|
||||||
for (; it1 != g_blockman.m_block_index.end(); it1++)
|
for (; it1 != g_blockman.m_block_index.end(); ++it1)
|
||||||
delete (*it1);
|
delete (*it1);
|
||||||
g_blockman.m_block_index.clear();
|
g_blockman.m_block_index.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <nameclaim.h>
|
#include <nameclaim.h>
|
||||||
#include <policy/feerate.h>
|
#include <policy/feerate.h>
|
||||||
#include <protocol.h> // For CMessageHeader::MessageStartChars
|
#include <protocol.h> // For CMessageHeader::MessageStartChars
|
||||||
|
#include <primitives/robin_hood.h>
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <txmempool.h> // For CTxMemPool::cs
|
#include <txmempool.h> // For CTxMemPool::cs
|
||||||
|
@ -144,6 +145,7 @@ extern CBlockPolicyEstimator feeEstimator;
|
||||||
extern CTxMemPool mempool;
|
extern CTxMemPool mempool;
|
||||||
extern Mutex g_best_block_mutex;
|
extern Mutex g_best_block_mutex;
|
||||||
extern std::condition_variable g_best_block_cv;
|
extern std::condition_variable g_best_block_cv;
|
||||||
|
extern std::atomic_bool g_is_mempool_loaded;
|
||||||
extern uint256 g_best_block;
|
extern uint256 g_best_block;
|
||||||
extern std::atomic_bool fImporting;
|
extern std::atomic_bool fImporting;
|
||||||
extern std::atomic_bool fReindex;
|
extern std::atomic_bool fReindex;
|
||||||
|
@ -428,15 +430,31 @@ struct CBlockIndexWorkComparator
|
||||||
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
|
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CBlockMapHasher
|
||||||
|
{
|
||||||
|
std::size_t operator()(const uint256& hash) const;
|
||||||
|
std::size_t operator()(const CBlockIndex* block) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct CBlockIndexHashComparator
|
struct CBlockIndexHashComparator
|
||||||
{
|
{
|
||||||
using is_transparent = void;
|
|
||||||
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
|
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
|
||||||
bool operator()(const CBlockIndex* pa, const uint256& hash) const;
|
bool operator()(const CBlockIndex* pa, const uint256& hash) const;
|
||||||
bool operator()(const uint256& hash, const CBlockIndex* pa) const;
|
bool operator()(const uint256& hash, const CBlockIndex* pa) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::set<CBlockIndex*, CBlockIndexHashComparator> BlockMap;
|
struct BlockMap : public robin_hood::unordered_set<CBlockIndex*, CBlockMapHasher, CBlockIndexHashComparator>
|
||||||
|
{
|
||||||
|
inline iterator find(const uint256& hash)
|
||||||
|
{
|
||||||
|
return robin_hood::unordered_set<CBlockIndex*, CBlockMapHasher, CBlockIndexHashComparator>::find(hash, robin_hood::is_transparent_tag());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const_iterator find(const uint256& hash) const
|
||||||
|
{
|
||||||
|
return robin_hood::unordered_set<CBlockIndex*, CBlockMapHasher, CBlockIndexHashComparator>::find(hash, robin_hood::is_transparent_tag());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
|
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
|
||||||
|
|
|
@ -326,9 +326,6 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet
|
||||||
if (nValue <= 0)
|
if (nValue <= 0)
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
|
||||||
|
|
||||||
if (nValue > curBalance)
|
|
||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
|
|
||||||
|
|
||||||
// Parse Bitcoin address
|
// Parse Bitcoin address
|
||||||
const CScript scriptPubKey = prefix + GetScriptForDestination(address);
|
const CScript scriptPubKey = prefix + GetScriptForDestination(address);
|
||||||
|
|
||||||
|
@ -1188,7 +1185,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
|
||||||
|
|
||||||
// Tally
|
// Tally
|
||||||
CAmount nAmount = 0;
|
CAmount nAmount = 0;
|
||||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
for (const auto& pairWtx : pwallet->mapWallet) {
|
||||||
const CWalletTx& wtx = pairWtx.second;
|
const CWalletTx& wtx = pairWtx.second;
|
||||||
if (wtx.IsCoinBase() || !locked_chain->checkFinalTx(*wtx.tx)) {
|
if (wtx.IsCoinBase() || !locked_chain->checkFinalTx(*wtx.tx)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1252,7 +1249,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
|
||||||
|
|
||||||
// Tally
|
// Tally
|
||||||
CAmount nAmount = 0;
|
CAmount nAmount = 0;
|
||||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
for (const auto& pairWtx : pwallet->mapWallet) {
|
||||||
const CWalletTx& wtx = pairWtx.second;
|
const CWalletTx& wtx = pairWtx.second;
|
||||||
if (wtx.IsCoinBase() || !locked_chain->checkFinalTx(*wtx.tx)) {
|
if (wtx.IsCoinBase() || !locked_chain->checkFinalTx(*wtx.tx)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1677,7 +1674,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
||||||
|
|
||||||
// Tally
|
// Tally
|
||||||
std::map<CTxDestination, tallyitem> mapTally;
|
std::map<CTxDestination, tallyitem> mapTally;
|
||||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
for (const auto& pairWtx : pwallet->mapWallet) {
|
||||||
const CWalletTx& wtx = pairWtx.second;
|
const CWalletTx& wtx = pairWtx.second;
|
||||||
|
|
||||||
if (wtx.IsCoinBase() || !locked_chain.checkFinalTx(*wtx.tx)) {
|
if (wtx.IsCoinBase() || !locked_chain.checkFinalTx(*wtx.tx)) {
|
||||||
|
@ -1730,7 +1727,6 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
||||||
for (auto item_it = start; item_it != end; ++item_it)
|
for (auto item_it = start; item_it != end; ++item_it)
|
||||||
{
|
{
|
||||||
const CTxDestination& address = item_it->first;
|
const CTxDestination& address = item_it->first;
|
||||||
const std::string& label = item_it->second.name;
|
|
||||||
auto it = mapTally.find(address);
|
auto it = mapTally.find(address);
|
||||||
if (it == mapTally.end() && !fIncludeEmpty)
|
if (it == mapTally.end() && !fIncludeEmpty)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1745,6 +1741,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
||||||
fIsWatchonly = (*it).second.fIsWatchonly;
|
fIsWatchonly = (*it).second.fIsWatchonly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& label = item_it->second.name;
|
||||||
if (by_label)
|
if (by_label)
|
||||||
{
|
{
|
||||||
tallyitem& _item = label_tally[label];
|
tallyitem& _item = label_tally[label];
|
||||||
|
@ -1761,6 +1758,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
|
||||||
obj.pushKV("amount", ValueFromAmount(nAmount));
|
obj.pushKV("amount", ValueFromAmount(nAmount));
|
||||||
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
|
||||||
obj.pushKV("label", label);
|
obj.pushKV("label", label);
|
||||||
|
obj.pushKV("purpose", item_it->second.purpose);
|
||||||
UniValue transactions(UniValue::VARR);
|
UniValue transactions(UniValue::VARR);
|
||||||
if (it != mapTally.end())
|
if (it != mapTally.end())
|
||||||
{
|
{
|
||||||
|
@ -2219,7 +2217,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
|
||||||
|
|
||||||
UniValue transactions(UniValue::VARR);
|
UniValue transactions(UniValue::VARR);
|
||||||
|
|
||||||
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
|
for (const auto& pairWtx : pwallet->mapWallet) {
|
||||||
CWalletTx tx = pairWtx.second;
|
CWalletTx tx = pairWtx.second;
|
||||||
|
|
||||||
if (depth == -1 || abs(tx.GetDepthInMainChain(*locked_chain)) < depth) {
|
if (depth == -1 || abs(tx.GetDepthInMainChain(*locked_chain)) < depth) {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include <wallet/fees.h>
|
#include <wallet/fees.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
@ -66,7 +66,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet)
|
||||||
{
|
{
|
||||||
LOCK(cs_wallets);
|
LOCK(cs_wallets);
|
||||||
assert(wallet);
|
assert(wallet);
|
||||||
std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
|
auto i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
|
||||||
if (i == vpwallets.end()) return false;
|
if (i == vpwallets.end()) return false;
|
||||||
vpwallets.erase(i);
|
vpwallets.erase(i);
|
||||||
return true;
|
return true;
|
||||||
|
@ -265,7 +265,7 @@ std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& p
|
||||||
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
|
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
|
auto it = mapWallet.find(hash);
|
||||||
if (it == mapWallet.end())
|
if (it == mapWallet.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &(it->second);
|
return &(it->second);
|
||||||
|
@ -737,7 +737,7 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||||
std::set<uint256> result;
|
std::set<uint256> result;
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
|
auto it = mapWallet.find(txid);
|
||||||
if (it == mapWallet.end())
|
if (it == mapWallet.end())
|
||||||
return result;
|
return result;
|
||||||
const CWalletTx& wtx = it->second;
|
const CWalletTx& wtx = it->second;
|
||||||
|
@ -746,11 +746,16 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||||
|
|
||||||
for (const CTxIn& txin : wtx.tx->vin)
|
for (const CTxIn& txin : wtx.tx->vin)
|
||||||
{
|
{
|
||||||
if (mapTxSpends.count(txin.prevout) <= 1)
|
auto hitTx = mapTxSpends.find(txin.prevout.hash);
|
||||||
|
if (hitTx == mapTxSpends.end())
|
||||||
|
continue;
|
||||||
|
auto hitN = hitTx->second.find(txin.prevout.n);
|
||||||
|
if (hitN == hitTx->second.end())
|
||||||
|
continue;
|
||||||
|
if (hitN->second.size() <= 1U)
|
||||||
continue; // No conflict if zero or one spends
|
continue; // No conflict if zero or one spends
|
||||||
range = mapTxSpends.equal_range(txin.prevout);
|
for (auto& spend: hitN->second)
|
||||||
for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it)
|
result.insert(spend);
|
||||||
result.insert(_it->second);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -758,8 +763,14 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||||
bool CWallet::HasWalletSpend(const uint256& txid) const
|
bool CWallet::HasWalletSpend(const uint256& txid) const
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
|
auto hitTx = mapTxSpends.find(txid);
|
||||||
return (iter != mapTxSpends.end() && iter->first.hash == txid);
|
if (hitTx == mapTxSpends.end())
|
||||||
|
return false;
|
||||||
|
for (auto& kvp: hitTx->second) {
|
||||||
|
if (!kvp.second.empty())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::Flush(bool shutdown)
|
void CWallet::Flush(bool shutdown)
|
||||||
|
@ -767,7 +778,7 @@ void CWallet::Flush(bool shutdown)
|
||||||
database->Flush(shutdown);
|
database->Flush(shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
|
void CWallet::SyncMetaData(const COutPoint& outPoint)
|
||||||
{
|
{
|
||||||
// We want all the wallet transactions in range to have the same metadata as
|
// We want all the wallet transactions in range to have the same metadata as
|
||||||
// the oldest (smallest nOrderPos).
|
// the oldest (smallest nOrderPos).
|
||||||
|
@ -775,22 +786,24 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
|
||||||
|
|
||||||
int nMinOrderPos = std::numeric_limits<int>::max();
|
int nMinOrderPos = std::numeric_limits<int>::max();
|
||||||
const CWalletTx* copyFrom = nullptr;
|
const CWalletTx* copyFrom = nullptr;
|
||||||
for (TxSpends::iterator it = range.first; it != range.second; ++it) {
|
|
||||||
const CWalletTx* wtx = &mapWallet.at(it->second);
|
auto hitTx = mapTxSpends.find(outPoint.hash);
|
||||||
|
if (hitTx != mapTxSpends.end()) {
|
||||||
|
auto hitN = hitTx->second.find(outPoint.n);
|
||||||
|
if (hitN != hitTx->second.end()) {
|
||||||
|
for (auto &spend: hitN->second) {
|
||||||
|
const CWalletTx *wtx = &mapWallet.at(spend);
|
||||||
if (wtx->nOrderPos < nMinOrderPos) {
|
if (wtx->nOrderPos < nMinOrderPos) {
|
||||||
nMinOrderPos = wtx->nOrderPos;
|
nMinOrderPos = wtx->nOrderPos;
|
||||||
copyFrom = wtx;
|
copyFrom = wtx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!copyFrom) {
|
if (!copyFrom) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now copy data from copyFrom to rest:
|
// Now copy data from copyFrom to rest:
|
||||||
for (TxSpends::iterator it = range.first; it != range.second; ++it)
|
for (auto &hash: hitN->second) {
|
||||||
{
|
|
||||||
const uint256& hash = it->second;
|
|
||||||
CWalletTx *copyTo = &mapWallet.at(hash);
|
CWalletTx *copyTo = &mapWallet.at(hash);
|
||||||
if (copyFrom == copyTo) continue;
|
if (copyFrom == copyTo) continue;
|
||||||
assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
|
assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
|
||||||
|
@ -805,6 +818,8 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
|
||||||
// cached members not copied on purpose
|
// cached members not copied on purpose
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Outpoint is spent if any non-conflicted transaction
|
* Outpoint is spent if any non-conflicted transaction
|
||||||
|
@ -812,14 +827,15 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
|
||||||
*/
|
*/
|
||||||
bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const
|
bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const
|
||||||
{
|
{
|
||||||
const COutPoint outpoint(hash, n);
|
auto hitTx = mapTxSpends.find(hash);
|
||||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
|
if (hitTx == mapTxSpends.end())
|
||||||
range = mapTxSpends.equal_range(outpoint);
|
return false;
|
||||||
|
auto hitN = hitTx->second.find(n);
|
||||||
|
if (hitN == hitTx->second.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
|
for (auto& wtxid: hitN->second) {
|
||||||
{
|
auto mit = mapWallet.find(wtxid);
|
||||||
const uint256& wtxid = it->second;
|
|
||||||
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
|
|
||||||
if (mit != mapWallet.end()) {
|
if (mit != mapWallet.end()) {
|
||||||
int depth = mit->second.GetDepthInMainChain(locked_chain);
|
int depth = mit->second.GetDepthInMainChain(locked_chain);
|
||||||
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
|
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
|
||||||
|
@ -831,13 +847,9 @@ bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash
|
||||||
|
|
||||||
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
|
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
|
||||||
{
|
{
|
||||||
mapTxSpends.insert(std::make_pair(outpoint, wtxid));
|
mapTxSpends[outpoint.hash][outpoint.n].push_back(wtxid);
|
||||||
|
|
||||||
setLockedCoins.erase(outpoint);
|
setLockedCoins.erase(outpoint);
|
||||||
|
SyncMetaData(outpoint);
|
||||||
std::pair<TxSpends::iterator, TxSpends::iterator> range;
|
|
||||||
range = mapTxSpends.equal_range(outpoint);
|
|
||||||
SyncMetaData(range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1022,7 +1034,7 @@ void CWallet::MarkDirty()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
for (std::pair<const uint256, CWalletTx>& item : mapWallet)
|
for (auto& item : mapWallet)
|
||||||
item.second.MarkDirty();
|
item.second.MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1124,7 +1136,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts only if not already there, returns tx inserted or tx found
|
// Inserts only if not already there, returns tx inserted or tx found
|
||||||
std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
|
auto ret = mapWallet.emplace(hash, wtxIn);
|
||||||
CWalletTx& wtx = (*ret.first).second;
|
CWalletTx& wtx = (*ret.first).second;
|
||||||
wtx.BindWallet(this);
|
wtx.BindWallet(this);
|
||||||
bool fInsertedNew = ret.second;
|
bool fInsertedNew = ret.second;
|
||||||
|
@ -1234,13 +1246,19 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::St
|
||||||
|
|
||||||
if (!block_hash.IsNull()) {
|
if (!block_hash.IsNull()) {
|
||||||
for (const CTxIn& txin : tx.vin) {
|
for (const CTxIn& txin : tx.vin) {
|
||||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
|
auto hitTx = mapTxSpends.find(txin.prevout.hash);
|
||||||
while (range.first != range.second) {
|
if (hitTx == mapTxSpends.end())
|
||||||
if (range.first->second != tx.GetHash()) {
|
continue;
|
||||||
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
|
auto hitN = hitTx->second.find(txin.prevout.n);
|
||||||
MarkConflicted(block_hash, range.first->second);
|
if (hitN == hitTx->second.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto& spend: hitN->second) {
|
||||||
|
if (spend != tx.GetHash()) {
|
||||||
|
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n",
|
||||||
|
tx.GetHash().ToString(), block_hash.ToString(), spend.ToString(), hitTx->first.ToString(), hitN->first);
|
||||||
|
MarkConflicted(block_hash, spend);
|
||||||
}
|
}
|
||||||
range.first++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1259,7 +1277,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::St
|
||||||
for (const CTxOut& txout: tx.vout) {
|
for (const CTxOut& txout: tx.vout) {
|
||||||
// extract addresses and check if they match with an unused keypool key
|
// extract addresses and check if they match with an unused keypool key
|
||||||
for (const auto& keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
|
for (const auto& keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
|
||||||
std::map<CKeyID, int64_t>::const_iterator mi = m_pool_key_to_index.find(keyid);
|
auto mi = m_pool_key_to_index.find(keyid);
|
||||||
if (mi != m_pool_key_to_index.end()) {
|
if (mi != m_pool_key_to_index.end()) {
|
||||||
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
|
WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__);
|
||||||
MarkReserveKeysAsUsed(mi->second);
|
MarkReserveKeysAsUsed(mi->second);
|
||||||
|
@ -1325,7 +1343,7 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui
|
||||||
uint256 now = *todo.begin();
|
uint256 now = *todo.begin();
|
||||||
todo.erase(now);
|
todo.erase(now);
|
||||||
done.insert(now);
|
done.insert(now);
|
||||||
auto it = mapWallet.find(now);
|
it = mapWallet.find(now);
|
||||||
assert(it != mapWallet.end());
|
assert(it != mapWallet.end());
|
||||||
CWalletTx& wtx = it->second;
|
CWalletTx& wtx = it->second;
|
||||||
int currentconfirm = wtx.GetDepthInMainChain(locked_chain);
|
int currentconfirm = wtx.GetDepthInMainChain(locked_chain);
|
||||||
|
@ -1341,12 +1359,14 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui
|
||||||
batch.WriteTx(wtx);
|
batch.WriteTx(wtx);
|
||||||
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
|
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
|
||||||
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
|
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
|
||||||
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
|
auto hitTx = mapTxSpends.find(now);
|
||||||
while (iter != mapTxSpends.end() && iter->first.hash == now) {
|
if (hitTx != mapTxSpends.end()) {
|
||||||
if (!done.count(iter->second)) {
|
for (auto &kvp: hitTx->second) {
|
||||||
todo.insert(iter->second);
|
for (auto &spent: kvp.second) {
|
||||||
|
if (!done.count(spent))
|
||||||
|
todo.insert(spent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iter++;
|
|
||||||
}
|
}
|
||||||
// If a transaction changes 'conflicted' state, that changes the balance
|
// If a transaction changes 'conflicted' state, that changes the balance
|
||||||
// available of the outputs it spends. So force those to be recomputed
|
// available of the outputs it spends. So force those to be recomputed
|
||||||
|
@ -1395,12 +1415,14 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
|
||||||
wtx.MarkDirty();
|
wtx.MarkDirty();
|
||||||
batch.WriteTx(wtx);
|
batch.WriteTx(wtx);
|
||||||
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
|
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
|
||||||
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
|
auto hitTx = mapTxSpends.find(now);
|
||||||
while (iter != mapTxSpends.end() && iter->first.hash == now) {
|
if (hitTx != mapTxSpends.end()) {
|
||||||
if (!done.count(iter->second)) {
|
for (auto &kvp: hitTx->second) {
|
||||||
todo.insert(iter->second);
|
for (auto &spent: kvp.second) {
|
||||||
|
if (!done.count(spent))
|
||||||
|
todo.insert(spent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iter++;
|
|
||||||
}
|
}
|
||||||
// If a transaction changes 'conflicted' state, that changes the balance
|
// If a transaction changes 'conflicted' state, that changes the balance
|
||||||
// available of the outputs it spends. So force those to be recomputed
|
// available of the outputs it spends. So force those to be recomputed
|
||||||
|
@ -1489,7 +1511,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
auto mi = mapWallet.find(txin.prevout.hash);
|
||||||
if (mi != mapWallet.end())
|
if (mi != mapWallet.end())
|
||||||
{
|
{
|
||||||
const CWalletTx& prev = (*mi).second;
|
const CWalletTx& prev = (*mi).second;
|
||||||
|
@ -1515,7 +1537,7 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
|
auto mi = mapWallet.find(txin.prevout.hash);
|
||||||
if (mi != mapWallet.end())
|
if (mi != mapWallet.end())
|
||||||
{
|
{
|
||||||
const CWalletTx& prev = (*mi).second;
|
const CWalletTx& prev = (*mi).second;
|
||||||
|
@ -2166,7 +2188,7 @@ void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
|
||||||
std::map<int64_t, CWalletTx*> mapSorted;
|
std::map<int64_t, CWalletTx*> mapSorted;
|
||||||
|
|
||||||
// Sort pending wallet transactions based on their initial wallet insertion order
|
// Sort pending wallet transactions based on their initial wallet insertion order
|
||||||
for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
|
for (auto& item : mapWallet) {
|
||||||
const uint256& wtxid = item.first;
|
const uint256& wtxid = item.first;
|
||||||
CWalletTx& wtx = item.second;
|
CWalletTx& wtx = item.second;
|
||||||
assert(wtx.GetHash() == wtxid);
|
assert(wtx.GetHash() == wtxid);
|
||||||
|
@ -2594,7 +2616,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
|
||||||
solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey); // this is a slow call
|
solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey); // this is a slow call
|
||||||
spendable = solvable;
|
spendable = solvable;
|
||||||
computedSolvable = true;
|
computedSolvable = true;
|
||||||
};
|
}
|
||||||
if (computeSolvable && !computedSolvable)
|
if (computeSolvable && !computedSolvable)
|
||||||
solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey);
|
solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey);
|
||||||
|
|
||||||
|
@ -2757,7 +2779,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
|
||||||
bnb_used = false;
|
bnb_used = false;
|
||||||
coin_selection_params.use_bnb = false;
|
coin_selection_params.use_bnb = false;
|
||||||
|
|
||||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
|
auto it = mapWallet.find(outpoint.hash);
|
||||||
if (it != mapWallet.end())
|
if (it != mapWallet.end())
|
||||||
{
|
{
|
||||||
const CWalletTx& wtx = it->second;
|
const CWalletTx& wtx = it->second;
|
||||||
|
@ -2819,7 +2841,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx)
|
||||||
// sign the new tx
|
// sign the new tx
|
||||||
int nIn = 0;
|
int nIn = 0;
|
||||||
for (auto& input : tx.vin) {
|
for (auto& input : tx.vin) {
|
||||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(input.prevout.hash);
|
auto mi = mapWallet.find(input.prevout.hash);
|
||||||
if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
|
if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4128,7 +4150,7 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
|
||||||
// iterate over all their outputs
|
// iterate over all their outputs
|
||||||
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
|
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
|
||||||
// ... and all their affected keys
|
// ... and all their affected keys
|
||||||
std::map<CKeyID, int>::iterator rit = mapKeyFirstBlock.find(keyid);
|
auto rit = mapKeyFirstBlock.find(keyid);
|
||||||
if (rit != mapKeyFirstBlock.end() && *height < rit->second)
|
if (rit != mapKeyFirstBlock.end() && *height < rit->second)
|
||||||
rit->second = *height;
|
rit->second = *height;
|
||||||
}
|
}
|
||||||
|
@ -4641,7 +4663,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
||||||
for (const CWalletTx& wtxOld : vWtx)
|
for (const CWalletTx& wtxOld : vWtx)
|
||||||
{
|
{
|
||||||
uint256 hash = wtxOld.GetHash();
|
uint256 hash = wtxOld.GetHash();
|
||||||
std::map<uint256, CWalletTx>::iterator mi = walletInstance->mapWallet.find(hash);
|
auto mi = walletInstance->mapWallet.find(hash);
|
||||||
if (mi != walletInstance->mapWallet.end())
|
if (mi != walletInstance->mapWallet.end())
|
||||||
{
|
{
|
||||||
const CWalletTx* copyFrom = &wtxOld;
|
const CWalletTx* copyFrom = &wtxOld;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <interfaces/handler.h>
|
#include <interfaces/handler.h>
|
||||||
#include <outputtype.h>
|
#include <outputtype.h>
|
||||||
#include <policy/feerate.h>
|
#include <policy/feerate.h>
|
||||||
|
#include <primitives/robin_hood.h>
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
|
@ -29,7 +30,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <stdint.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -786,7 +786,7 @@ private:
|
||||||
* detect and report conflicts (double-spends or
|
* detect and report conflicts (double-spends or
|
||||||
* mutated transactions where the mutant gets mined).
|
* mutated transactions where the mutant gets mined).
|
||||||
*/
|
*/
|
||||||
typedef std::multimap<COutPoint, uint256> TxSpends;
|
typedef robin_hood::unordered_map<uint256, robin_hood::unordered_map<uint32_t, std::vector<uint256>>> TxSpends;
|
||||||
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
|
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
|
||||||
void AddToSpends(const COutPoint& outpoint, const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void AddToSpends(const COutPoint& outpoint, const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
void AddToSpends(const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void AddToSpends(const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
@ -812,7 +812,7 @@ private:
|
||||||
/* Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
|
/* Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
|
||||||
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void SyncMetaData(const COutPoint& outpoint);
|
||||||
|
|
||||||
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
|
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
|
||||||
* Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
|
* Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
|
||||||
|
@ -920,10 +920,10 @@ public:
|
||||||
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|
||||||
// Map from Key ID to key metadata.
|
// Map from Key ID to key metadata.
|
||||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_wallet);
|
robin_hood::unordered_map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
||||||
|
|
||||||
// Map from Script ID to key metadata (for watch-only keys).
|
// Map from Script ID to key metadata (for watch-only keys).
|
||||||
std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
|
robin_hood::unordered_map<CScriptID, CKeyMetadata> m_script_metadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
|
|
Loading…
Reference in a new issue