mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-12 16:17:53 +00:00
Merge #13644: 0.16: Remaining backports for 0.16.2
d9c563095d
qa: Initialize lockstack to prevent null pointer deref (MarcoFalke)21dd5127a4
gui: Show messages as text not html (Wladimir J. van der Laan)f78e7f6589
[qt] send: Clear All also resets coin control options (Sjors Provoost)657dfc5bca
Fix csBestBlock/cvBlockChange waiting in rpc/mining (Pieter Wuille)88d1a649a2
Consensus: Fix bug when compiler do not support __builtin_clz* (532479301)b72c0bd4c9
[qa] Add a test for merkle proof malleation (Suhas Daftuar)6b9dc8ceae
have verifytxoutproof check the number of txns in proof structure (Gregory Sanders)ed82e7176d
wallet: Erase wtxOrderd wtx pointer on removeprunedfunds (MarcoFalke)e15e3a9ddd
Remove boost dependency (boost/assign/std/vector.hpp) (practicalswift)10621995ed
Fix incorrect tests (practicalswift)170b309981
Make tests pass after 2020 (Bernhard M. Wiedemann)cfc6f7413b
[rpcwallet] Clamp walletpassphrase value at 100M seconds (Suhas Daftuar)bf1f150190
rpc: fix type mistmatch in listreceivedbyaddress (joemphilips)2291774bd5
[trivial] Add newlines to end of log messages. (John Newbery)cf6feb7837
qt: Avoid resetting on resetguisettigs=0 (MarcoFalke)cbdabef35e
qa: Fix wallet_listreceivedby race (MarcoFalke)79c4fff9ed
[tests] Fixed intermittent failure in p2p_sendheaders.py. (lmanners)c04a4a5ae9
Remove useless mapRequest tracking that just effects Qt display. (Matt Corallo) Pull request description: Some gui/doc/rpc/qa backports Tree-SHA512: f1e918d2ca6016fc7c5d5adf5d537553a1769731e2dcac788edf02c7354387861ec5bcd0cbf3c833c1485d500c55a73a2799a8b39ed14477524ac46b4ff2332d
This commit is contained in:
commit
7f27af22b0
@ -82,12 +82,12 @@ void static inline WriteBE64(unsigned char* ptr, uint64_t x)
|
|||||||
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
|
/** Return the smallest number n such that (x >> n) == 0 (or 64 if the highest bit in x is set. */
|
||||||
uint64_t static inline CountBits(uint64_t x)
|
uint64_t static inline CountBits(uint64_t x)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DECL___BUILTIN_CLZL
|
#if HAVE_DECL___BUILTIN_CLZL
|
||||||
if (sizeof(unsigned long) >= sizeof(uint64_t)) {
|
if (sizeof(unsigned long) >= sizeof(uint64_t)) {
|
||||||
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
|
return x ? 8 * sizeof(unsigned long) - __builtin_clzl(x) : 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_DECL___BUILTIN_CLZLL
|
#if HAVE_DECL___BUILTIN_CLZLL
|
||||||
if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
|
if (sizeof(unsigned long long) >= sizeof(uint64_t)) {
|
||||||
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
|
return x ? 8 * sizeof(unsigned long long) - __builtin_clzll(x) : 0;
|
||||||
}
|
}
|
||||||
|
@ -684,7 +684,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
|
|||||||
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!ActivateBestChain(state, chainparams)) {
|
if (!ActivateBestChain(state, chainparams)) {
|
||||||
LogPrintf("Failed to connect best block");
|
LogPrintf("Failed to connect best block\n");
|
||||||
StartShutdown();
|
StartShutdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,12 @@ public:
|
|||||||
* returns the merkle root, or 0 in case of failure
|
* returns the merkle root, or 0 in case of failure
|
||||||
*/
|
*/
|
||||||
uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
|
uint256 ExtractMatches(std::vector<uint256> &vMatch, std::vector<unsigned int> &vnIndex);
|
||||||
|
|
||||||
|
/** Get number of transactions the merkle proof is indicating for cross-reference with
|
||||||
|
* local blockchain knowledge.
|
||||||
|
*/
|
||||||
|
unsigned int GetNumTransactions() const { return nTransactions; };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1221,9 +1221,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|||||||
if (!push) {
|
if (!push) {
|
||||||
vNotFound.push_back(inv);
|
vNotFound.push_back(inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track requests for our stuff.
|
|
||||||
GetMainSignals().Inventory(inv.hash);
|
|
||||||
}
|
}
|
||||||
} // release cs_main
|
} // release cs_main
|
||||||
|
|
||||||
@ -1908,9 +1905,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
pfrom->AskFor(inv);
|
pfrom->AskFor(inv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track requests for our stuff
|
|
||||||
GetMainSignals().Inventory(inv.hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ int main(int argc, char *argv[])
|
|||||||
// Allow parameter interaction before we create the options model
|
// Allow parameter interaction before we create the options model
|
||||||
app.parameterSetup();
|
app.parameterSetup();
|
||||||
// Load GUI settings from QSettings
|
// Load GUI settings from QSettings
|
||||||
app.createOptionsModel(gArgs.IsArgSet("-resetguisettings"));
|
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
|
||||||
|
|
||||||
// Subscribe to global signals from core
|
// Subscribe to global signals from core
|
||||||
uiInterface.InitMessage.connect(InitMessage);
|
uiInterface.InitMessage.connect(InitMessage);
|
||||||
|
@ -923,6 +923,7 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
|
|||||||
|
|
||||||
showNormalIfMinimized();
|
showNormalIfMinimized();
|
||||||
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
|
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
|
||||||
|
mBox.setTextFormat(Qt::PlainText);
|
||||||
int r = mBox.exec();
|
int r = mBox.exec();
|
||||||
if (ret != nullptr)
|
if (ret != nullptr)
|
||||||
*ret = r == QMessageBox::Ok;
|
*ret = r == QMessageBox::Ok;
|
||||||
|
@ -27,8 +27,6 @@ static const bool DEFAULT_SPLASHSCREEN = true;
|
|||||||
#define COLOR_BAREADDRESS QColor(140, 140, 140)
|
#define COLOR_BAREADDRESS QColor(140, 140, 140)
|
||||||
/* Transaction list -- TX status decoration - open until date */
|
/* Transaction list -- TX status decoration - open until date */
|
||||||
#define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255)
|
#define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255)
|
||||||
/* Transaction list -- TX status decoration - offline */
|
|
||||||
#define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192)
|
|
||||||
/* Transaction list -- TX status decoration - danger, tx needs attention */
|
/* Transaction list -- TX status decoration - danger, tx needs attention */
|
||||||
#define COLOR_TX_STATUS_DANGER QColor(200, 100, 100)
|
#define COLOR_TX_STATUS_DANGER QColor(200, 100, 100)
|
||||||
/* Transaction list -- TX status decoration - default color */
|
/* Transaction list -- TX status decoration - default color */
|
||||||
|
@ -375,6 +375,12 @@ void SendCoinsDialog::on_sendButton_clicked()
|
|||||||
|
|
||||||
void SendCoinsDialog::clear()
|
void SendCoinsDialog::clear()
|
||||||
{
|
{
|
||||||
|
// Clear coin control settings
|
||||||
|
CoinControlDialog::coinControl()->UnSelectAll();
|
||||||
|
ui->checkBoxCoinControlChange->setChecked(false);
|
||||||
|
ui->lineEditCoinControlChange->clear();
|
||||||
|
coinControlUpdateLabels();
|
||||||
|
|
||||||
// Remove entries until only one left
|
// Remove entries until only one left
|
||||||
while(ui->entries->count())
|
while(ui->entries->count())
|
||||||
{
|
{
|
||||||
|
@ -36,8 +36,6 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
|
|||||||
int nDepth = wtx.GetDepthInMainChain();
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
if (nDepth < 0)
|
if (nDepth < 0)
|
||||||
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
|
return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
|
||||||
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
|
||||||
return tr("%1/offline").arg(nDepth);
|
|
||||||
else if (nDepth == 0)
|
else if (nDepth == 0)
|
||||||
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
|
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
|
||||||
else if (nDepth < 6)
|
else if (nDepth < 6)
|
||||||
@ -61,14 +59,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
|
|||||||
CAmount nNet = nCredit - nDebit;
|
CAmount nNet = nCredit - nDebit;
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
|
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
|
||||||
int nRequests = wtx.GetRequestCount();
|
|
||||||
if (nRequests != -1)
|
|
||||||
{
|
|
||||||
if (nRequests == 0)
|
|
||||||
strHTML += tr(", has not been successfully broadcast yet");
|
|
||||||
else if (nRequests > 0)
|
|
||||||
strHTML += tr(", broadcast through %n node(s)", "", nRequests);
|
|
||||||
}
|
|
||||||
strHTML += "<br>";
|
strHTML += "<br>";
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
|
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
|
||||||
|
@ -205,10 +205,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
|||||||
if (wtx.IsInMainChain())
|
if (wtx.IsInMainChain())
|
||||||
{
|
{
|
||||||
status.matures_in = wtx.GetBlocksToMaturity();
|
status.matures_in = wtx.GetBlocksToMaturity();
|
||||||
|
|
||||||
// Check if the block was requested by anyone
|
|
||||||
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
|
||||||
status.status = TransactionStatus::MaturesWarning;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -226,10 +222,6 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
|||||||
{
|
{
|
||||||
status.status = TransactionStatus::Conflicted;
|
status.status = TransactionStatus::Conflicted;
|
||||||
}
|
}
|
||||||
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
|
||||||
{
|
|
||||||
status.status = TransactionStatus::Offline;
|
|
||||||
}
|
|
||||||
else if (status.depth == 0)
|
else if (status.depth == 0)
|
||||||
{
|
{
|
||||||
status.status = TransactionStatus::Unconfirmed;
|
status.status = TransactionStatus::Unconfirmed;
|
||||||
|
@ -21,7 +21,7 @@ class TransactionStatus
|
|||||||
public:
|
public:
|
||||||
TransactionStatus():
|
TransactionStatus():
|
||||||
countsForBalance(false), sortKey(""),
|
countsForBalance(false), sortKey(""),
|
||||||
matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
|
matures_in(0), status(Unconfirmed), depth(0), open_for(0), cur_num_blocks(-1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
@ -29,14 +29,12 @@ public:
|
|||||||
/// Normal (sent/received) transactions
|
/// Normal (sent/received) transactions
|
||||||
OpenUntilDate, /**< Transaction not yet final, waiting for date */
|
OpenUntilDate, /**< Transaction not yet final, waiting for date */
|
||||||
OpenUntilBlock, /**< Transaction not yet final, waiting for block */
|
OpenUntilBlock, /**< Transaction not yet final, waiting for block */
|
||||||
Offline, /**< Not sent to any other nodes **/
|
|
||||||
Unconfirmed, /**< Not yet mined into a block **/
|
Unconfirmed, /**< Not yet mined into a block **/
|
||||||
Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/
|
Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/
|
||||||
Conflicted, /**< Conflicts with other transaction or mempool **/
|
Conflicted, /**< Conflicts with other transaction or mempool **/
|
||||||
Abandoned, /**< Abandoned from the wallet **/
|
Abandoned, /**< Abandoned from the wallet **/
|
||||||
/// Generated (mined) transactions
|
/// Generated (mined) transactions
|
||||||
Immature, /**< Mined but waiting for maturity */
|
Immature, /**< Mined but waiting for maturity */
|
||||||
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */
|
|
||||||
NotAccepted /**< Mined but not accepted */
|
NotAccepted /**< Mined but not accepted */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -308,9 +308,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
|
|||||||
case TransactionStatus::OpenUntilDate:
|
case TransactionStatus::OpenUntilDate:
|
||||||
status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
|
status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
|
||||||
break;
|
break;
|
||||||
case TransactionStatus::Offline:
|
|
||||||
status = tr("Offline");
|
|
||||||
break;
|
|
||||||
case TransactionStatus::Unconfirmed:
|
case TransactionStatus::Unconfirmed:
|
||||||
status = tr("Unconfirmed");
|
status = tr("Unconfirmed");
|
||||||
break;
|
break;
|
||||||
@ -329,9 +326,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
|
|||||||
case TransactionStatus::Immature:
|
case TransactionStatus::Immature:
|
||||||
status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
|
status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
|
||||||
break;
|
break;
|
||||||
case TransactionStatus::MaturesWarning:
|
|
||||||
status = tr("This block was not received by any other nodes and will probably not be accepted!");
|
|
||||||
break;
|
|
||||||
case TransactionStatus::NotAccepted:
|
case TransactionStatus::NotAccepted:
|
||||||
status = tr("Generated but not accepted");
|
status = tr("Generated but not accepted");
|
||||||
break;
|
break;
|
||||||
@ -469,8 +463,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx)
|
|||||||
case TransactionStatus::OpenUntilBlock:
|
case TransactionStatus::OpenUntilBlock:
|
||||||
case TransactionStatus::OpenUntilDate:
|
case TransactionStatus::OpenUntilDate:
|
||||||
return COLOR_TX_STATUS_OPENUNTILDATE;
|
return COLOR_TX_STATUS_OPENUNTILDATE;
|
||||||
case TransactionStatus::Offline:
|
|
||||||
return COLOR_TX_STATUS_OFFLINE;
|
|
||||||
case TransactionStatus::Unconfirmed:
|
case TransactionStatus::Unconfirmed:
|
||||||
return QIcon(":/icons/transaction_0");
|
return QIcon(":/icons/transaction_0");
|
||||||
case TransactionStatus::Abandoned:
|
case TransactionStatus::Abandoned:
|
||||||
@ -493,7 +485,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx)
|
|||||||
int part = (wtx->status.depth * 4 / total) + 1;
|
int part = (wtx->status.depth * 4 / total) + 1;
|
||||||
return QIcon(QString(":/icons/transaction_%1").arg(part));
|
return QIcon(QString(":/icons/transaction_%1").arg(part));
|
||||||
}
|
}
|
||||||
case TransactionStatus::MaturesWarning:
|
|
||||||
case TransactionStatus::NotAccepted:
|
case TransactionStatus::NotAccepted:
|
||||||
return QIcon(":/icons/transaction_0");
|
return QIcon(":/icons/transaction_0");
|
||||||
default:
|
default:
|
||||||
|
@ -477,7 +477,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
|
|||||||
checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
|
checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
|
||||||
|
|
||||||
WaitableLock lock(csBestBlock);
|
WaitableLock lock(csBestBlock);
|
||||||
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
|
while (hashBestBlock == hashWatchedChain && IsRPCRunning())
|
||||||
{
|
{
|
||||||
if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
|
if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
|
||||||
{
|
{
|
||||||
|
@ -290,7 +290,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
|
|||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
|
"1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
|
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||||
@ -306,11 +306,16 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
|
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]) || mapBlockIndex[merkleBlock.header.GetHash()]->nTx == 0)
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
|
||||||
|
|
||||||
for (const uint256& hash : vMatch)
|
// Check if proof is valid, only add results if so
|
||||||
|
if (mapBlockIndex[merkleBlock.header.GetHash()]->nTx == merkleBlock.txn.GetNumTransactions()) {
|
||||||
|
for (const uint256& hash : vMatch) {
|
||||||
res.push_back(hash.GetHex());
|
res.push_back(hash.GetHex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/sync.cpp
19
src/sync.cpp
@ -73,7 +73,7 @@ struct LockData {
|
|||||||
std::mutex dd_mutex;
|
std::mutex dd_mutex;
|
||||||
} static lockdata;
|
} static lockdata;
|
||||||
|
|
||||||
static thread_local std::unique_ptr<LockStack> lockstack;
|
static thread_local LockStack g_lockstack;
|
||||||
|
|
||||||
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
|
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
|
||||||
{
|
{
|
||||||
@ -103,21 +103,18 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
|
|||||||
|
|
||||||
static void push_lock(void* c, const CLockLocation& locklocation)
|
static void push_lock(void* c, const CLockLocation& locklocation)
|
||||||
{
|
{
|
||||||
if (!lockstack)
|
|
||||||
lockstack.reset(new LockStack);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
|
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
|
||||||
|
|
||||||
lockstack->push_back(std::make_pair(c, locklocation));
|
g_lockstack.push_back(std::make_pair(c, locklocation));
|
||||||
|
|
||||||
for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
|
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
|
||||||
if (i.first == c)
|
if (i.first == c)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
|
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
|
||||||
if (lockdata.lockorders.count(p1))
|
if (lockdata.lockorders.count(p1))
|
||||||
continue;
|
continue;
|
||||||
lockdata.lockorders[p1] = (*lockstack);
|
lockdata.lockorders[p1] = g_lockstack;
|
||||||
|
|
||||||
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
|
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
|
||||||
lockdata.invlockorders.insert(p2);
|
lockdata.invlockorders.insert(p2);
|
||||||
@ -128,7 +125,7 @@ static void push_lock(void* c, const CLockLocation& locklocation)
|
|||||||
|
|
||||||
static void pop_lock()
|
static void pop_lock()
|
||||||
{
|
{
|
||||||
(*lockstack).pop_back();
|
g_lockstack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
|
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
|
||||||
@ -144,14 +141,14 @@ void LeaveCritical()
|
|||||||
std::string LocksHeld()
|
std::string LocksHeld()
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
for (const std::pair<void*, CLockLocation> & i : *lockstack)
|
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
|
||||||
result += i.second.ToString() + std::string("\n");
|
result += i.second.ToString() + std::string("\n");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
||||||
{
|
{
|
||||||
for (const std::pair<void*, CLockLocation> & i : *lockstack)
|
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
|
||||||
if (i.first == cs)
|
if (i.first == cs)
|
||||||
return;
|
return;
|
||||||
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
|
fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
|
||||||
@ -160,7 +157,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
|
|||||||
|
|
||||||
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
||||||
{
|
{
|
||||||
for (const std::pair<void*, CLockLocation>& i : *lockstack) {
|
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
|
||||||
if (i.first == cs) {
|
if (i.first == cs) {
|
||||||
fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
|
fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
|
||||||
abort();
|
abort();
|
||||||
|
@ -256,14 +256,14 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
|
|||||||
ar = r.get_array();
|
ar = r.get_array();
|
||||||
BOOST_CHECK_EQUAL(ar.size(), 0);
|
BOOST_CHECK_EQUAL(ar.size(), 0);
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 1607731200 true")));
|
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 9907731200 true")));
|
||||||
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
|
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
|
||||||
ar = r.get_array();
|
ar = r.get_array();
|
||||||
o1 = ar[0].get_obj();
|
o1 = ar[0].get_obj();
|
||||||
adr = find_value(o1, "address");
|
adr = find_value(o1, "address");
|
||||||
UniValue banned_until = find_value(o1, "banned_until");
|
UniValue banned_until = find_value(o1, "banned_until");
|
||||||
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
|
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
|
||||||
BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
|
BOOST_CHECK_EQUAL(banned_until.get_int64(), 9907731200); // absolute time check
|
||||||
|
|
||||||
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
|
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
|
||||||
|
|
||||||
|
@ -6,11 +6,8 @@
|
|||||||
#include <support/allocators/zeroafterfree.h>
|
#include <support/allocators/zeroafterfree.h>
|
||||||
#include <test/test_bitcoin.h>
|
#include <test/test_bitcoin.h>
|
||||||
|
|
||||||
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
using namespace boost::assign; // bring 'operator+=()' into scope
|
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(streams_vector_writer)
|
BOOST_AUTO_TEST_CASE(streams_vector_writer)
|
||||||
@ -80,14 +77,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
|
|||||||
|
|
||||||
// Degenerate case
|
// Degenerate case
|
||||||
|
|
||||||
key += '\x00','\x00';
|
key.push_back('\x00');
|
||||||
|
key.push_back('\x00');
|
||||||
ds.Xor(key);
|
ds.Xor(key);
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
std::string(expected_xor.begin(), expected_xor.end()),
|
std::string(expected_xor.begin(), expected_xor.end()),
|
||||||
std::string(ds.begin(), ds.end()));
|
std::string(ds.begin(), ds.end()));
|
||||||
|
|
||||||
in += '\x0f','\xf0';
|
in.push_back('\x0f');
|
||||||
expected_xor += '\xf0','\x0f';
|
in.push_back('\xf0');
|
||||||
|
expected_xor.push_back('\xf0');
|
||||||
|
expected_xor.push_back('\x0f');
|
||||||
|
|
||||||
// Single character key
|
// Single character key
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
|
|||||||
ds.insert(ds.begin(), in.begin(), in.end());
|
ds.insert(ds.begin(), in.begin(), in.end());
|
||||||
key.clear();
|
key.clear();
|
||||||
|
|
||||||
key += '\xff';
|
key.push_back('\xff');
|
||||||
ds.Xor(key);
|
ds.Xor(key);
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
std::string(expected_xor.begin(), expected_xor.end()),
|
std::string(expected_xor.begin(), expected_xor.end()),
|
||||||
@ -105,14 +105,17 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
|
|||||||
|
|
||||||
in.clear();
|
in.clear();
|
||||||
expected_xor.clear();
|
expected_xor.clear();
|
||||||
in += '\xf0','\x0f';
|
in.push_back('\xf0');
|
||||||
expected_xor += '\x0f','\x00';
|
in.push_back('\x0f');
|
||||||
|
expected_xor.push_back('\x0f');
|
||||||
|
expected_xor.push_back('\x00');
|
||||||
|
|
||||||
ds.clear();
|
ds.clear();
|
||||||
ds.insert(ds.begin(), in.begin(), in.end());
|
ds.insert(ds.begin(), in.begin(), in.end());
|
||||||
|
|
||||||
key.clear();
|
key.clear();
|
||||||
key += '\xff','\x0f';
|
key.push_back('\xff');
|
||||||
|
key.push_back('\x0f');
|
||||||
|
|
||||||
ds.Xor(key);
|
ds.Xor(key);
|
||||||
BOOST_CHECK_EQUAL(
|
BOOST_CHECK_EQUAL(
|
||||||
|
@ -210,6 +210,7 @@ CChain& chainActive = g_chainstate.chainActive;
|
|||||||
CBlockIndex *pindexBestHeader = nullptr;
|
CBlockIndex *pindexBestHeader = nullptr;
|
||||||
CWaitableCriticalSection csBestBlock;
|
CWaitableCriticalSection csBestBlock;
|
||||||
CConditionVariable cvBlockChange;
|
CConditionVariable cvBlockChange;
|
||||||
|
uint256 hashBestBlock;
|
||||||
int nScriptCheckThreads = 0;
|
int nScriptCheckThreads = 0;
|
||||||
std::atomic_bool fImporting(false);
|
std::atomic_bool fImporting(false);
|
||||||
std::atomic_bool fReindex(false);
|
std::atomic_bool fReindex(false);
|
||||||
@ -2151,7 +2152,11 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
|
|||||||
// New best block
|
// New best block
|
||||||
mempool.AddTransactionsUpdated(1);
|
mempool.AddTransactionsUpdated(1);
|
||||||
|
|
||||||
|
{
|
||||||
|
WaitableLock lock(csBestBlock);
|
||||||
|
hashBestBlock = pindexNew->GetBlockHash();
|
||||||
cvBlockChange.notify_all();
|
cvBlockChange.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> warningMessages;
|
std::vector<std::string> warningMessages;
|
||||||
if (!IsInitialBlockDownload())
|
if (!IsInitialBlockDownload())
|
||||||
|
@ -166,6 +166,7 @@ extern uint64_t nLastBlockWeight;
|
|||||||
extern const std::string strMessageMagic;
|
extern const std::string strMessageMagic;
|
||||||
extern CWaitableCriticalSection csBestBlock;
|
extern CWaitableCriticalSection csBestBlock;
|
||||||
extern CConditionVariable cvBlockChange;
|
extern CConditionVariable cvBlockChange;
|
||||||
|
extern uint256 hashBestBlock;
|
||||||
extern std::atomic_bool fImporting;
|
extern std::atomic_bool fImporting;
|
||||||
extern std::atomic_bool fReindex;
|
extern std::atomic_bool fReindex;
|
||||||
extern int nScriptCheckThreads;
|
extern int nScriptCheckThreads;
|
||||||
|
@ -26,7 +26,6 @@ struct MainSignalsInstance {
|
|||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
||||||
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
||||||
boost::signals2::signal<void (const uint256 &)> Inventory;
|
|
||||||
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
||||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
||||||
@ -81,7 +80,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||||||
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
||||||
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
|
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
|
||||||
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||||
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
|
||||||
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
||||||
@ -90,7 +88,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
|
||||||
g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||||
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
|
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
|
||||||
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
||||||
@ -106,7 +103,6 @@ void UnregisterAllValidationInterfaces() {
|
|||||||
}
|
}
|
||||||
g_signals.m_internals->BlockChecked.disconnect_all_slots();
|
g_signals.m_internals->BlockChecked.disconnect_all_slots();
|
||||||
g_signals.m_internals->Broadcast.disconnect_all_slots();
|
g_signals.m_internals->Broadcast.disconnect_all_slots();
|
||||||
g_signals.m_internals->Inventory.disconnect_all_slots();
|
|
||||||
g_signals.m_internals->SetBestChain.disconnect_all_slots();
|
g_signals.m_internals->SetBestChain.disconnect_all_slots();
|
||||||
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
|
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
|
||||||
g_signals.m_internals->BlockConnected.disconnect_all_slots();
|
g_signals.m_internals->BlockConnected.disconnect_all_slots();
|
||||||
@ -172,12 +168,6 @@ void CMainSignals::SetBestChain(const CBlockLocator &locator) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::Inventory(const uint256 &hash) {
|
|
||||||
m_internals->m_schedulerClient.AddToProcessQueue([hash, this] {
|
|
||||||
m_internals->Inventory(hash);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
|
void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
|
||||||
m_internals->Broadcast(nBestBlockTime, connman);
|
m_internals->Broadcast(nBestBlockTime, connman);
|
||||||
}
|
}
|
||||||
|
@ -101,12 +101,6 @@ protected:
|
|||||||
* Called on a background thread.
|
* Called on a background thread.
|
||||||
*/
|
*/
|
||||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||||
/**
|
|
||||||
* Notifies listeners about an inventory item being seen on the network.
|
|
||||||
*
|
|
||||||
* Called on a background thread.
|
|
||||||
*/
|
|
||||||
virtual void Inventory(const uint256 &hash) {}
|
|
||||||
/** Tells listeners to broadcast their data. */
|
/** Tells listeners to broadcast their data. */
|
||||||
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
|
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
|
||||||
/**
|
/**
|
||||||
@ -157,7 +151,6 @@ public:
|
|||||||
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
||||||
void SetBestChain(const CBlockLocator &);
|
void SetBestChain(const CBlockLocator &);
|
||||||
void Inventory(const uint256 &);
|
|
||||||
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
|
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
|
||||||
void BlockChecked(const CBlock&, const CValidationState&);
|
void BlockChecked(const CBlock&, const CValidationState&);
|
||||||
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
||||||
|
@ -1537,7 +1537,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
|
|||||||
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
|
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
|
||||||
" \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
|
" \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
|
||||||
" \"txids\": [\n"
|
" \"txids\": [\n"
|
||||||
" n, (numeric) The ids of transactions received with the address \n"
|
" \"txid\", (string) The ids of transactions received with the address \n"
|
||||||
" ...\n"
|
" ...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
@ -2322,8 +2322,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
|
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"passphrase\" (string, required) The wallet passphrase\n"
|
"1. \"passphrase\" (string, required) The wallet passphrase\n"
|
||||||
"2. timeout (numeric, required) The time to keep the decryption key in seconds. Limited to at most 1073741824 (2^30) seconds.\n"
|
"2. timeout (numeric, required) The time to keep the decryption key in seconds; capped at 100000000 (~3 years).\n"
|
||||||
" Any value greater than 1073741824 seconds will be set to 1073741824 seconds.\n"
|
|
||||||
"\nNote:\n"
|
"\nNote:\n"
|
||||||
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
|
"Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
|
||||||
"time that overrides the old one.\n"
|
"time that overrides the old one.\n"
|
||||||
@ -2358,9 +2357,10 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
|
|||||||
if (nSleepTime < 0) {
|
if (nSleepTime < 0) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
|
||||||
}
|
}
|
||||||
// Clamp timeout to 2^30 seconds
|
// Clamp timeout
|
||||||
if (nSleepTime > (int64_t)1 << 30) {
|
constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
|
||||||
nSleepTime = (int64_t)1 << 30;
|
if (nSleepTime > MAX_SLEEP_TIME) {
|
||||||
|
nSleepTime = MAX_SLEEP_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strWalletPass.length() > 0)
|
if (strWalletPass.length() > 0)
|
||||||
|
@ -891,7 +891,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
|
|||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (!walletdb.WriteTx(wtx)) {
|
if (!walletdb.WriteTx(wtx)) {
|
||||||
LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetHash().ToString());
|
LogPrintf("%s: Updating walletdb tx %s failed\n", __func__, wtx.GetHash().ToString());
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,11 +913,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
|||||||
CWalletTx& wtx = (*ret.first).second;
|
CWalletTx& wtx = (*ret.first).second;
|
||||||
wtx.BindWallet(this);
|
wtx.BindWallet(this);
|
||||||
bool fInsertedNew = ret.second;
|
bool fInsertedNew = ret.second;
|
||||||
if (fInsertedNew)
|
if (fInsertedNew) {
|
||||||
{
|
|
||||||
wtx.nTimeReceived = GetAdjustedTime();
|
wtx.nTimeReceived = GetAdjustedTime();
|
||||||
wtx.nOrderPos = IncOrderPosNext(&walletdb);
|
wtx.nOrderPos = IncOrderPosNext(&walletdb);
|
||||||
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
||||||
wtx.nTimeSmart = ComputeTimeSmart(wtx);
|
wtx.nTimeSmart = ComputeTimeSmart(wtx);
|
||||||
AddToSpends(hash);
|
AddToSpends(hash);
|
||||||
}
|
}
|
||||||
@ -987,9 +986,12 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
|||||||
bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
|
bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
|
||||||
{
|
{
|
||||||
uint256 hash = wtxIn.GetHash();
|
uint256 hash = wtxIn.GetHash();
|
||||||
CWalletTx& wtx = mapWallet.emplace(hash, wtxIn).first->second;
|
const auto& ins = mapWallet.emplace(hash, wtxIn);
|
||||||
|
CWalletTx& wtx = ins.first->second;
|
||||||
wtx.BindWallet(this);
|
wtx.BindWallet(this);
|
||||||
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
if (/* insertion took place */ ins.second) {
|
||||||
|
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
|
||||||
|
}
|
||||||
AddToSpends(hash);
|
AddToSpends(hash);
|
||||||
for (const CTxIn& txin : wtx.tx->vin) {
|
for (const CTxIn& txin : wtx.tx->vin) {
|
||||||
auto it = mapWallet.find(txin.prevout.hash);
|
auto it = mapWallet.find(txin.prevout.hash);
|
||||||
@ -1506,45 +1508,6 @@ int64_t CWalletTx::GetTxTime() const
|
|||||||
return n ? n : nTimeReceived;
|
return n ? n : nTimeReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CWalletTx::GetRequestCount() const
|
|
||||||
{
|
|
||||||
// Returns -1 if it wasn't being tracked
|
|
||||||
int nRequests = -1;
|
|
||||||
{
|
|
||||||
LOCK(pwallet->cs_wallet);
|
|
||||||
if (IsCoinBase())
|
|
||||||
{
|
|
||||||
// Generated block
|
|
||||||
if (!hashUnset())
|
|
||||||
{
|
|
||||||
std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
|
|
||||||
if (mi != pwallet->mapRequestCount.end())
|
|
||||||
nRequests = (*mi).second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Did anyone request this transaction?
|
|
||||||
std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
|
|
||||||
if (mi != pwallet->mapRequestCount.end())
|
|
||||||
{
|
|
||||||
nRequests = (*mi).second;
|
|
||||||
|
|
||||||
// How about the block it's in?
|
|
||||||
if (nRequests == 0 && !hashUnset())
|
|
||||||
{
|
|
||||||
std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
|
|
||||||
if (_mi != pwallet->mapRequestCount.end())
|
|
||||||
nRequests = (*_mi).second;
|
|
||||||
else
|
|
||||||
nRequests = 1; // If it's in someone else's block it must have got out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
|
||||||
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
|
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
|
||||||
{
|
{
|
||||||
@ -3085,9 +3048,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track how many getdata requests our transaction gets
|
|
||||||
mapRequestCount[wtxNew.GetHash()] = 0;
|
|
||||||
|
|
||||||
// Get the inserted-CWalletTx from mapWallet so that the
|
// Get the inserted-CWalletTx from mapWallet so that the
|
||||||
// fInMempool flag is cached properly
|
// fInMempool flag is cached properly
|
||||||
CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
|
CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
|
||||||
@ -3165,8 +3125,11 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
|
|||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapWallet
|
AssertLockHeld(cs_wallet); // mapWallet
|
||||||
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
|
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
|
||||||
for (uint256 hash : vHashOut)
|
for (uint256 hash : vHashOut) {
|
||||||
mapWallet.erase(hash);
|
const auto& it = mapWallet.find(hash);
|
||||||
|
wtxOrdered.erase(it->second.m_it_wtxOrdered);
|
||||||
|
mapWallet.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
if (nZapSelectTxRet == DB_NEED_REWRITE)
|
if (nZapSelectTxRet == DB_NEED_REWRITE)
|
||||||
{
|
{
|
||||||
|
@ -327,6 +327,7 @@ public:
|
|||||||
char fFromMe;
|
char fFromMe;
|
||||||
std::string strFromAccount;
|
std::string strFromAccount;
|
||||||
int64_t nOrderPos; //!< position in ordered transaction list
|
int64_t nOrderPos; //!< position in ordered transaction list
|
||||||
|
std::multimap<int64_t, std::pair<CWalletTx*, CAccountingEntry*>>::const_iterator m_it_wtxOrdered;
|
||||||
|
|
||||||
// memory only
|
// memory only
|
||||||
mutable bool fDebitCached;
|
mutable bool fDebitCached;
|
||||||
@ -478,7 +479,6 @@ public:
|
|||||||
bool IsTrusted() const;
|
bool IsTrusted() const;
|
||||||
|
|
||||||
int64_t GetTxTime() const;
|
int64_t GetTxTime() const;
|
||||||
int GetRequestCount() const;
|
|
||||||
|
|
||||||
// RelayWalletTransaction may only be called if fBroadcastTransactions!
|
// RelayWalletTransaction may only be called if fBroadcastTransactions!
|
||||||
bool RelayWalletTransaction(CConnman* connman);
|
bool RelayWalletTransaction(CConnman* connman);
|
||||||
@ -834,7 +834,6 @@ public:
|
|||||||
|
|
||||||
int64_t nOrderPosNext;
|
int64_t nOrderPosNext;
|
||||||
uint64_t nAccountingEntryNumber;
|
uint64_t nAccountingEntryNumber;
|
||||||
std::map<uint256, int> mapRequestCount;
|
|
||||||
|
|
||||||
std::map<CTxDestination, CAddressBookData> mapAddressBook;
|
std::map<CTxDestination, CAddressBookData> mapAddressBook;
|
||||||
|
|
||||||
@ -1043,16 +1042,6 @@ public:
|
|||||||
|
|
||||||
const std::string& GetAccountName(const CScript& scriptPubKey) const;
|
const std::string& GetAccountName(const CScript& scriptPubKey) const;
|
||||||
|
|
||||||
void Inventory(const uint256 &hash) override
|
|
||||||
{
|
|
||||||
{
|
|
||||||
LOCK(cs_wallet);
|
|
||||||
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
|
|
||||||
if (mi != mapRequestCount.end())
|
|
||||||
(*mi).second++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
|
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
|
||||||
|
|
||||||
unsigned int GetKeyPoolSize()
|
unsigned int GetKeyPoolSize()
|
||||||
|
@ -116,6 +116,7 @@ class BaseNode(P2PInterface):
|
|||||||
|
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_blockhash_announced = None
|
self.last_blockhash_announced = None
|
||||||
|
self.recent_headers_announced = []
|
||||||
|
|
||||||
def send_get_data(self, block_hashes):
|
def send_get_data(self, block_hashes):
|
||||||
"""Request data for a list of block hashes."""
|
"""Request data for a list of block hashes."""
|
||||||
@ -163,40 +164,45 @@ class BaseNode(P2PInterface):
|
|||||||
def on_headers(self, message):
|
def on_headers(self, message):
|
||||||
if len(message.headers):
|
if len(message.headers):
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
message.headers[-1].calc_sha256()
|
for x in message.headers:
|
||||||
|
x.calc_sha256()
|
||||||
|
# append because headers may be announced over multiple messages.
|
||||||
|
self.recent_headers_announced.append(x.sha256)
|
||||||
self.last_blockhash_announced = message.headers[-1].sha256
|
self.last_blockhash_announced = message.headers[-1].sha256
|
||||||
|
|
||||||
def clear_last_announcement(self):
|
def clear_block_announcements(self):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_message.pop("inv", None)
|
self.last_message.pop("inv", None)
|
||||||
self.last_message.pop("headers", None)
|
self.last_message.pop("headers", None)
|
||||||
|
self.recent_headers_announced = []
|
||||||
|
|
||||||
def check_last_announcement(self, headers=None, inv=None):
|
|
||||||
"""Test whether the last announcement received had the right header or the right inv.
|
|
||||||
|
|
||||||
inv and headers should be lists of block hashes."""
|
def check_last_headers_announcement(self, headers):
|
||||||
|
"""Test whether the last headers announcements received are right.
|
||||||
|
Headers may be announced across more than one message."""
|
||||||
|
test_function = lambda: (len(self.recent_headers_announced) >= len(headers))
|
||||||
|
wait_until(test_function, timeout=60, lock=mininode_lock)
|
||||||
|
with mininode_lock:
|
||||||
|
assert_equal(self.recent_headers_announced, headers)
|
||||||
|
self.block_announced = False
|
||||||
|
self.last_message.pop("headers", None)
|
||||||
|
self.recent_headers_announced = []
|
||||||
|
|
||||||
|
def check_last_inv_announcement(self, inv):
|
||||||
|
"""Test whether the last announcement received had the right inv.
|
||||||
|
inv should be a list of block hashes."""
|
||||||
|
|
||||||
test_function = lambda: self.block_announced
|
test_function = lambda: self.block_announced
|
||||||
wait_until(test_function, timeout=60, lock=mininode_lock)
|
wait_until(test_function, timeout=60, lock=mininode_lock)
|
||||||
|
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
self.block_announced = False
|
|
||||||
|
|
||||||
compare_inv = []
|
compare_inv = []
|
||||||
if "inv" in self.last_message:
|
if "inv" in self.last_message:
|
||||||
compare_inv = [x.hash for x in self.last_message["inv"].inv]
|
compare_inv = [x.hash for x in self.last_message["inv"].inv]
|
||||||
if inv is not None:
|
|
||||||
assert_equal(compare_inv, inv)
|
assert_equal(compare_inv, inv)
|
||||||
|
self.block_announced = False
|
||||||
compare_headers = []
|
|
||||||
if "headers" in self.last_message:
|
|
||||||
compare_headers = [x.sha256 for x in self.last_message["headers"].headers]
|
|
||||||
if headers is not None:
|
|
||||||
assert_equal(compare_headers, headers)
|
|
||||||
|
|
||||||
self.last_message.pop("inv", None)
|
self.last_message.pop("inv", None)
|
||||||
self.last_message.pop("headers", None)
|
|
||||||
|
|
||||||
class SendHeadersTest(BitcoinTestFramework):
|
class SendHeadersTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
@ -206,8 +212,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
def mine_blocks(self, count):
|
def mine_blocks(self, count):
|
||||||
"""Mine count blocks and return the new tip."""
|
"""Mine count blocks and return the new tip."""
|
||||||
|
|
||||||
# Clear out last block announcement from each p2p listener
|
# Clear out block announcements from each p2p listener
|
||||||
[x.clear_last_announcement() for x in self.nodes[0].p2ps]
|
[x.clear_block_announcements() for x in self.nodes[0].p2ps]
|
||||||
self.nodes[0].generate(count)
|
self.nodes[0].generate(count)
|
||||||
return int(self.nodes[0].getbestblockhash(), 16)
|
return int(self.nodes[0].getbestblockhash(), 16)
|
||||||
|
|
||||||
@ -222,7 +228,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
sync_blocks(self.nodes, wait=0.1)
|
sync_blocks(self.nodes, wait=0.1)
|
||||||
for x in self.nodes[0].p2ps:
|
for x in self.nodes[0].p2ps:
|
||||||
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
|
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
|
||||||
x.clear_last_announcement()
|
x.clear_block_announcements()
|
||||||
|
|
||||||
tip_height = self.nodes[1].getblockcount()
|
tip_height = self.nodes[1].getblockcount()
|
||||||
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
|
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
|
||||||
@ -255,25 +261,25 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
|
tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
|
||||||
tip_hash = int(tip["hash"], 16)
|
tip_hash = int(tip["hash"], 16)
|
||||||
|
|
||||||
inv_node.check_last_announcement(inv=[tip_hash], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip_hash])
|
||||||
test_node.check_last_announcement(inv=[tip_hash], headers=[])
|
test_node.check_last_inv_announcement(inv=[tip_hash])
|
||||||
|
|
||||||
self.log.info("Verify getheaders with null locator and valid hashstop returns headers.")
|
self.log.info("Verify getheaders with null locator and valid hashstop returns headers.")
|
||||||
test_node.clear_last_announcement()
|
test_node.clear_block_announcements()
|
||||||
test_node.send_get_headers(locator=[], hashstop=tip_hash)
|
test_node.send_get_headers(locator=[], hashstop=tip_hash)
|
||||||
test_node.check_last_announcement(headers=[tip_hash])
|
test_node.check_last_headers_announcement(headers=[tip_hash])
|
||||||
|
|
||||||
self.log.info("Verify getheaders with null locator and invalid hashstop does not return headers.")
|
self.log.info("Verify getheaders with null locator and invalid hashstop does not return headers.")
|
||||||
block = create_block(int(tip["hash"], 16), create_coinbase(tip["height"] + 1), tip["mediantime"] + 1)
|
block = create_block(int(tip["hash"], 16), create_coinbase(tip["height"] + 1), tip["mediantime"] + 1)
|
||||||
block.solve()
|
block.solve()
|
||||||
test_node.send_header_for_blocks([block])
|
test_node.send_header_for_blocks([block])
|
||||||
test_node.clear_last_announcement()
|
test_node.clear_block_announcements()
|
||||||
test_node.send_get_headers(locator=[], hashstop=int(block.hash, 16))
|
test_node.send_get_headers(locator=[], hashstop=int(block.hash, 16))
|
||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
assert_equal(test_node.block_announced, False)
|
assert_equal(test_node.block_announced, False)
|
||||||
inv_node.clear_last_announcement()
|
inv_node.clear_block_announcements()
|
||||||
test_node.send_message(msg_block(block))
|
test_node.send_message(msg_block(block))
|
||||||
inv_node.check_last_announcement(inv=[int(block.hash, 16)], headers=[])
|
inv_node.check_last_inv_announcement(inv=[int(block.hash, 16)])
|
||||||
|
|
||||||
def test_nonnull_locators(self, test_node, inv_node):
|
def test_nonnull_locators(self, test_node, inv_node):
|
||||||
tip = int(self.nodes[0].getbestblockhash(), 16)
|
tip = int(self.nodes[0].getbestblockhash(), 16)
|
||||||
@ -284,8 +290,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
for i in range(4):
|
for i in range(4):
|
||||||
old_tip = tip
|
old_tip = tip
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(inv=[tip], headers=[])
|
test_node.check_last_inv_announcement(inv=[tip])
|
||||||
# Try a few different responses; none should affect next announcement
|
# Try a few different responses; none should affect next announcement
|
||||||
if i == 0:
|
if i == 0:
|
||||||
# first request the block
|
# first request the block
|
||||||
@ -296,7 +302,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
test_node.send_get_headers(locator=[old_tip], hashstop=tip)
|
test_node.send_get_headers(locator=[old_tip], hashstop=tip)
|
||||||
test_node.send_get_data([tip])
|
test_node.send_get_data([tip])
|
||||||
test_node.wait_for_block(tip)
|
test_node.wait_for_block(tip)
|
||||||
test_node.clear_last_announcement() # since we requested headers...
|
test_node.clear_block_announcements() # since we requested headers...
|
||||||
elif i == 2:
|
elif i == 2:
|
||||||
# this time announce own block via headers
|
# this time announce own block via headers
|
||||||
height = self.nodes[0].getblockcount()
|
height = self.nodes[0].getblockcount()
|
||||||
@ -308,8 +314,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
test_node.wait_for_getdata([new_block.sha256])
|
test_node.wait_for_getdata([new_block.sha256])
|
||||||
test_node.send_message(msg_block(new_block))
|
test_node.send_message(msg_block(new_block))
|
||||||
test_node.sync_with_ping() # make sure this block is processed
|
test_node.sync_with_ping() # make sure this block is processed
|
||||||
inv_node.clear_last_announcement()
|
inv_node.clear_block_announcements()
|
||||||
test_node.clear_last_announcement()
|
test_node.clear_block_announcements()
|
||||||
|
|
||||||
self.log.info("Part 1: success!")
|
self.log.info("Part 1: success!")
|
||||||
self.log.info("Part 2: announce blocks with headers after sendheaders message...")
|
self.log.info("Part 2: announce blocks with headers after sendheaders message...")
|
||||||
@ -323,8 +329,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Now that we've synced headers, headers announcements should work
|
# Now that we've synced headers, headers announcements should work
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(headers=[tip])
|
test_node.check_last_headers_announcement(headers=[tip])
|
||||||
|
|
||||||
height = self.nodes[0].getblockcount() + 1
|
height = self.nodes[0].getblockcount() + 1
|
||||||
block_time += 10 # Advance far enough ahead
|
block_time += 10 # Advance far enough ahead
|
||||||
@ -368,8 +374,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
assert "inv" not in inv_node.last_message
|
assert "inv" not in inv_node.last_message
|
||||||
assert "headers" not in inv_node.last_message
|
assert "headers" not in inv_node.last_message
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(headers=[tip])
|
test_node.check_last_headers_announcement(headers=[tip])
|
||||||
height += 1
|
height += 1
|
||||||
block_time += 1
|
block_time += 1
|
||||||
|
|
||||||
@ -383,16 +389,16 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
# First try mining a reorg that can propagate with header announcement
|
# First try mining a reorg that can propagate with header announcement
|
||||||
new_block_hashes = self.mine_reorg(length=7)
|
new_block_hashes = self.mine_reorg(length=7)
|
||||||
tip = new_block_hashes[-1]
|
tip = new_block_hashes[-1]
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(headers=new_block_hashes)
|
test_node.check_last_headers_announcement(headers=new_block_hashes)
|
||||||
|
|
||||||
block_time += 8
|
block_time += 8
|
||||||
|
|
||||||
# Mine a too-large reorg, which should be announced with a single inv
|
# Mine a too-large reorg, which should be announced with a single inv
|
||||||
new_block_hashes = self.mine_reorg(length=8)
|
new_block_hashes = self.mine_reorg(length=8)
|
||||||
tip = new_block_hashes[-1]
|
tip = new_block_hashes[-1]
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(inv=[tip], headers=[])
|
test_node.check_last_inv_announcement(inv=[tip])
|
||||||
|
|
||||||
block_time += 9
|
block_time += 9
|
||||||
|
|
||||||
@ -401,15 +407,15 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Use getblocks/getdata
|
# Use getblocks/getdata
|
||||||
test_node.send_getblocks(locator=[fork_point])
|
test_node.send_getblocks(locator=[fork_point])
|
||||||
test_node.check_last_announcement(inv=new_block_hashes, headers=[])
|
test_node.check_last_inv_announcement(inv=new_block_hashes)
|
||||||
test_node.send_get_data(new_block_hashes)
|
test_node.send_get_data(new_block_hashes)
|
||||||
test_node.wait_for_block(new_block_hashes[-1])
|
test_node.wait_for_block(new_block_hashes[-1])
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
# Mine another block, still should get only an inv
|
# Mine another block, still should get only an inv
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(inv=[tip], headers=[])
|
test_node.check_last_inv_announcement(inv=[tip])
|
||||||
if i == 0:
|
if i == 0:
|
||||||
# Just get the data -- shouldn't cause headers announcements to resume
|
# Just get the data -- shouldn't cause headers announcements to resume
|
||||||
test_node.send_get_data([tip])
|
test_node.send_get_data([tip])
|
||||||
@ -434,8 +440,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
# New blocks should now be announced with header
|
# New blocks should now be announced with header
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
inv_node.check_last_announcement(inv=[tip], headers=[])
|
inv_node.check_last_inv_announcement(inv=[tip])
|
||||||
test_node.check_last_announcement(headers=[tip])
|
test_node.check_last_headers_announcement(headers=[tip])
|
||||||
|
|
||||||
self.log.info("Part 3: success!")
|
self.log.info("Part 3: success!")
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
|
from test_framework.mininode import FromHex, ToHex
|
||||||
|
from test_framework.messages import CMerkleBlock
|
||||||
|
|
||||||
class MerkleBlockTest(BitcoinTestFramework):
|
class MerkleBlockTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
@ -78,6 +80,27 @@ class MerkleBlockTest(BitcoinTestFramework):
|
|||||||
# We can't get a proof if we specify transactions from different blocks
|
# We can't get a proof if we specify transactions from different blocks
|
||||||
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3])
|
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[2].gettxoutproof, [txid1, txid3])
|
||||||
|
|
||||||
|
# Now we'll try tweaking a proof.
|
||||||
|
proof = self.nodes[3].gettxoutproof([txid1, txid2])
|
||||||
|
assert txid1 in self.nodes[0].verifytxoutproof(proof)
|
||||||
|
assert txid2 in self.nodes[1].verifytxoutproof(proof)
|
||||||
|
|
||||||
|
tweaked_proof = FromHex(CMerkleBlock(), proof)
|
||||||
|
|
||||||
|
# Make sure that our serialization/deserialization is working
|
||||||
|
assert txid1 in self.nodes[2].verifytxoutproof(ToHex(tweaked_proof))
|
||||||
|
|
||||||
|
# Check to see if we can go up the merkle tree and pass this off as a
|
||||||
|
# single-transaction block
|
||||||
|
tweaked_proof.txn.nTransactions = 1
|
||||||
|
tweaked_proof.txn.vHash = [tweaked_proof.header.hashMerkleRoot]
|
||||||
|
tweaked_proof.txn.vBits = [True] + [False]*7
|
||||||
|
|
||||||
|
for n in self.nodes:
|
||||||
|
assert not n.verifytxoutproof(ToHex(tweaked_proof))
|
||||||
|
|
||||||
|
# TODO: try more variants, eg transactions at different depths, and
|
||||||
|
# verify that the proofs are invalid
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MerkleBlockTest().main()
|
MerkleBlockTest().main()
|
||||||
|
@ -830,6 +830,52 @@ class BlockTransactions():
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
|
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
|
||||||
|
|
||||||
|
class CPartialMerkleTree():
|
||||||
|
def __init__(self):
|
||||||
|
self.nTransactions = 0
|
||||||
|
self.vHash = []
|
||||||
|
self.vBits = []
|
||||||
|
self.fBad = False
|
||||||
|
|
||||||
|
def deserialize(self, f):
|
||||||
|
self.nTransactions = struct.unpack("<i", f.read(4))[0]
|
||||||
|
self.vHash = deser_uint256_vector(f)
|
||||||
|
vBytes = deser_string(f)
|
||||||
|
self.vBits = []
|
||||||
|
for i in range(len(vBytes) * 8):
|
||||||
|
self.vBits.append(vBytes[i//8] & (1 << (i % 8)) != 0)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
r = b""
|
||||||
|
r += struct.pack("<i", self.nTransactions)
|
||||||
|
r += ser_uint256_vector(self.vHash)
|
||||||
|
vBytesArray = bytearray([0x00] * ((len(self.vBits) + 7)//8))
|
||||||
|
for i in range(len(self.vBits)):
|
||||||
|
vBytesArray[i // 8] |= self.vBits[i] << (i % 8)
|
||||||
|
r += ser_string(bytes(vBytesArray))
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits))
|
||||||
|
|
||||||
|
class CMerkleBlock():
|
||||||
|
def __init__(self):
|
||||||
|
self.header = CBlockHeader()
|
||||||
|
self.txn = CPartialMerkleTree()
|
||||||
|
|
||||||
|
def deserialize(self, f):
|
||||||
|
self.header.deserialize(f)
|
||||||
|
self.txn.deserialize(f)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
r = b""
|
||||||
|
r += self.header.serialize()
|
||||||
|
r += self.txn.serialize()
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "CMerkleBlock(header=%s, txn=%s)" % (repr(self.header), repr(self.txn))
|
||||||
|
|
||||||
|
|
||||||
# Objects that correspond to messages on the wire
|
# Objects that correspond to messages on the wire
|
||||||
class msg_version():
|
class msg_version():
|
||||||
|
@ -64,14 +64,15 @@ class WalletEncryptionTest(BitcoinTestFramework):
|
|||||||
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
|
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
|
||||||
# Check the timeout
|
# Check the timeout
|
||||||
# Check a time less than the limit
|
# Check a time less than the limit
|
||||||
expected_time = int(time.time()) + (1 << 30) - 600
|
MAX_VALUE = 100000000
|
||||||
self.nodes[0].walletpassphrase(passphrase2, (1 << 30) - 600)
|
expected_time = int(time.time()) + MAX_VALUE - 600
|
||||||
|
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
|
||||||
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
|
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
|
||||||
assert_greater_than_or_equal(actual_time, expected_time)
|
assert_greater_than_or_equal(actual_time, expected_time)
|
||||||
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
|
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
|
||||||
# Check a time greater than the limit
|
# Check a time greater than the limit
|
||||||
expected_time = int(time.time()) + (1 << 30) - 1
|
expected_time = int(time.time()) + MAX_VALUE - 1
|
||||||
self.nodes[0].walletpassphrase(passphrase2, (1 << 33))
|
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
|
||||||
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
|
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
|
||||||
assert_greater_than_or_equal(actual_time, expected_time)
|
assert_greater_than_or_equal(actual_time, expected_time)
|
||||||
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
|
assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
|
||||||
|
@ -6,10 +6,13 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (assert_array_result,
|
from test_framework.util import (
|
||||||
|
assert_array_result,
|
||||||
assert_equal,
|
assert_equal,
|
||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
)
|
sync_blocks,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ReceivedByTest(BitcoinTestFramework):
|
class ReceivedByTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
@ -18,6 +21,7 @@ class ReceivedByTest(BitcoinTestFramework):
|
|||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Generate block to get out of IBD
|
# Generate block to get out of IBD
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
self.log.info("listreceivedbyaddress Test")
|
self.log.info("listreceivedbyaddress Test")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user