mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 13:32:47 +01:00
58cb7e38f4
6262915
Add unit test for stale tip checking (Suhas Daftuar)83df257
Add CConnmanTest to mutate g_connman in tests (João Barbosa)ac7b37c
Connect to an extra outbound peer if our tip is stale (Suhas Daftuar)db32a65
Track tip update time and last new block announcement from each peer (Suhas Daftuar)2d4327d
net: Allow connecting to extra outbound peers (Suhas Daftuar) Pull request description: This is an alternative approach to #11534. Rather than disconnect an outbound peer when our tip looks stale, instead try to connect to an additional outbound peer. Periodically, check to see if we have more outbound peers than we target (ie if any extra peers are in use), and if so, disconnect the one that least recently announced a new block (breaking ties by choosing the newest peer that we connected to). Tree-SHA512: 8f19e910e0bb36867f81783e020af225f356451899adfc7ade1895d6d3bd5afe51c83759610dfd10c62090c4fe404efa0283b2f63fde0bd7da898a1aaa7fb281
235 lines
7.8 KiB
C++
235 lines
7.8 KiB
C++
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "test_dash.h"
|
|
|
|
#include "chainparams.h"
|
|
#include "consensus/consensus.h"
|
|
#include "consensus/validation.h"
|
|
#include "crypto/sha256.h"
|
|
#include "fs.h"
|
|
#include "key.h"
|
|
#include "validation.h"
|
|
#include "miner.h"
|
|
#include "net_processing.h"
|
|
#include "pubkey.h"
|
|
#include "random.h"
|
|
#include "txdb.h"
|
|
#include "txmempool.h"
|
|
#include "ui_interface.h"
|
|
#include "rpc/server.h"
|
|
#include "rpc/register.h"
|
|
#include "script/sigcache.h"
|
|
|
|
#include "evo/specialtx.h"
|
|
#include "evo/deterministicmns.h"
|
|
#include "evo/cbtx.h"
|
|
#include "llmq/quorums_init.h"
|
|
|
|
#include <memory>
|
|
|
|
void CConnmanTest::AddNode(CNode& node)
|
|
{
|
|
LOCK(g_connman->cs_vNodes);
|
|
g_connman->vNodes.push_back(&node);
|
|
}
|
|
|
|
void CConnmanTest::ClearNodes()
|
|
{
|
|
LOCK(g_connman->cs_vNodes);
|
|
g_connman->vNodes.clear();
|
|
}
|
|
|
|
uint256 insecure_rand_seed = GetRandHash();
|
|
FastRandomContext insecure_rand_ctx(insecure_rand_seed);
|
|
|
|
extern bool fPrintToConsole;
|
|
extern void noui_connect();
|
|
|
|
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
|
|
{
|
|
SHA256AutoDetect();
|
|
RandomInit();
|
|
ECC_Start();
|
|
BLSInit();
|
|
SetupEnvironment();
|
|
SetupNetworking();
|
|
InitSignatureCache();
|
|
InitScriptExecutionCache();
|
|
fPrintToDebugLog = false; // don't want to write to debug.log file
|
|
fCheckBlockIndex = true;
|
|
SelectParams(chainName);
|
|
evoDb = new CEvoDB(1 << 20, true, true);
|
|
deterministicMNManager = new CDeterministicMNManager(*evoDb);
|
|
noui_connect();
|
|
}
|
|
|
|
BasicTestingSetup::~BasicTestingSetup()
|
|
{
|
|
delete deterministicMNManager;
|
|
delete evoDb;
|
|
|
|
ECC_Stop();
|
|
}
|
|
|
|
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
|
|
{
|
|
const CChainParams& chainparams = Params();
|
|
// Ideally we'd move all the RPC tests to the functional testing framework
|
|
// instead of unit tests, but for now we need these here.
|
|
RegisterAllCoreRPCCommands(tableRPC);
|
|
ClearDatadirCache();
|
|
pathTemp = fs::temp_directory_path() / strprintf("test_dash_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
|
|
fs::create_directories(pathTemp);
|
|
gArgs.ForceSetArg("-datadir", pathTemp.string());
|
|
|
|
// Note that because we don't bother running a scheduler thread here,
|
|
// callbacks via CValidationInterface are unreliable, but that's OK,
|
|
// our unit tests aren't testing multiple parts of the code at once.
|
|
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
|
|
mempool.setSanityCheck(1.0);
|
|
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
|
|
connman = g_connman.get();
|
|
pblocktree = new CBlockTreeDB(1 << 20, true);
|
|
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
|
|
llmq::InitLLMQSystem(*evoDb, nullptr, true);
|
|
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
|
|
if (!LoadGenesisBlock(chainparams)) {
|
|
throw std::runtime_error("LoadGenesisBlock failed.");
|
|
}
|
|
{
|
|
CValidationState state;
|
|
if (!ActivateBestChain(state, chainparams)) {
|
|
throw std::runtime_error("ActivateBestChain failed.");
|
|
}
|
|
}
|
|
nScriptCheckThreads = 3;
|
|
for (int i=0; i < nScriptCheckThreads-1; i++)
|
|
threadGroup.create_thread(&ThreadScriptCheck);
|
|
peerLogic.reset(new PeerLogicValidation(connman, scheduler));
|
|
}
|
|
|
|
TestingSetup::~TestingSetup()
|
|
{
|
|
llmq::InterruptLLMQSystem();
|
|
threadGroup.interrupt_all();
|
|
threadGroup.join_all();
|
|
GetMainSignals().FlushBackgroundCallbacks();
|
|
GetMainSignals().UnregisterBackgroundSignalScheduler();
|
|
g_connman.reset();
|
|
peerLogic.reset();
|
|
UnloadBlockIndex();
|
|
delete pcoinsTip;
|
|
llmq::DestroyLLMQSystem();
|
|
delete pcoinsdbview;
|
|
delete pblocktree;
|
|
fs::remove_all(pathTemp);
|
|
}
|
|
|
|
TestChainSetup::TestChainSetup(int blockCount) : TestingSetup(CBaseChainParams::REGTEST)
|
|
{
|
|
// Generate a 100-block chain:
|
|
coinbaseKey.MakeNewKey(true);
|
|
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
|
for (int i = 0; i < blockCount; i++)
|
|
{
|
|
std::vector<CMutableTransaction> noTxns;
|
|
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
|
|
coinbaseTxns.push_back(*b.vtx[0]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new block with just given transactions, coinbase paying to
|
|
// scriptPubKey, and try to add it to the current chain.
|
|
//
|
|
CBlock
|
|
TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
|
{
|
|
const CChainParams& chainparams = Params();
|
|
auto block = CreateBlock(txns, scriptPubKey);
|
|
|
|
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
|
|
ProcessNewBlock(chainparams, shared_pblock, true, nullptr);
|
|
|
|
CBlock result = block;
|
|
return result;
|
|
}
|
|
|
|
CBlock TestChainSetup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey)
|
|
{
|
|
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
|
return CreateAndProcessBlock(txns, scriptPubKey);
|
|
}
|
|
|
|
CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
|
|
{
|
|
const CChainParams& chainparams = Params();
|
|
std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
|
|
CBlock& block = pblocktemplate->block;
|
|
|
|
std::vector<CTransactionRef> llmqCommitments;
|
|
for (const auto& tx : block.vtx) {
|
|
if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
|
|
llmqCommitments.emplace_back(tx);
|
|
}
|
|
}
|
|
|
|
// Replace mempool-selected txns with just coinbase plus passed-in txns:
|
|
block.vtx.resize(1);
|
|
// Re-add quorum commitments
|
|
block.vtx.insert(block.vtx.end(), llmqCommitments.begin(), llmqCommitments.end());
|
|
for (const CMutableTransaction& tx : txns)
|
|
block.vtx.push_back(MakeTransactionRef(tx));
|
|
|
|
// Manually update CbTx as we modified the block here
|
|
if (block.vtx[0]->nType == TRANSACTION_COINBASE) {
|
|
LOCK(cs_main);
|
|
CCbTx cbTx;
|
|
if (!GetTxPayload(*block.vtx[0], cbTx)) {
|
|
BOOST_ASSERT(false);
|
|
}
|
|
CValidationState state;
|
|
if (!CalcCbTxMerkleRootMNList(block, chainActive.Tip(), cbTx.merkleRootMNList, state)) {
|
|
BOOST_ASSERT(false);
|
|
}
|
|
if (!CalcCbTxMerkleRootQuorums(block, chainActive.Tip(), cbTx.merkleRootQuorums, state)) {
|
|
BOOST_ASSERT(false);
|
|
}
|
|
CMutableTransaction tmpTx = *block.vtx[0];
|
|
SetTxPayload(tmpTx, cbTx);
|
|
block.vtx[0] = MakeTransactionRef(tmpTx);
|
|
}
|
|
|
|
// IncrementExtraNonce creates a valid coinbase and merkleRoot
|
|
unsigned int extraNonce = 0;
|
|
IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
|
|
|
|
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
|
|
|
|
CBlock result = block;
|
|
return result;
|
|
}
|
|
|
|
CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns, const CKey& scriptKey)
|
|
{
|
|
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
|
return CreateBlock(txns, scriptPubKey);
|
|
}
|
|
|
|
TestChainSetup::~TestChainSetup()
|
|
{
|
|
}
|
|
|
|
|
|
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
|
|
CTransaction txn(tx);
|
|
return FromTx(txn);
|
|
}
|
|
|
|
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
|
|
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
|
|
spendsCoinbase, sigOpCount, lp);
|
|
}
|