Merge pull request #1 from floblockchain/flo-master
Pull in changes from master
This commit is contained in:
commit
df02b9c155
@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
|||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
define(_CLIENT_VERSION_MAJOR, 0)
|
define(_CLIENT_VERSION_MAJOR, 0)
|
||||||
define(_CLIENT_VERSION_MINOR, 15)
|
define(_CLIENT_VERSION_MINOR, 15)
|
||||||
define(_CLIENT_VERSION_REVISION, 0)
|
define(_CLIENT_VERSION_REVISION, 1)
|
||||||
define(_CLIENT_VERSION_BUILD, 1)
|
define(_CLIENT_VERSION_BUILD, 1)
|
||||||
define(_CLIENT_VERSION_IS_RELEASE, true)
|
define(_CLIENT_VERSION_IS_RELEASE, true)
|
||||||
define(_COPYRIGHT_YEAR, 2017)
|
define(_COPYRIGHT_YEAR, 2018)
|
||||||
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
define(_COPYRIGHT_HOLDERS,[The %s developers])
|
||||||
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[FLO Core]])
|
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[FLO Core]])
|
||||||
AC_INIT([FLO Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/floblockchain/flo/issues],[flo],[https://flo.cash/])
|
AC_INIT([FLO Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/floblockchain/flo/issues],[flo],[https://flo.cash/])
|
||||||
|
|||||||
@ -102,10 +102,10 @@ public:
|
|||||||
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1554098766; // April 1st, 2019
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1554098766; // April 1st, 2019
|
||||||
|
|
||||||
// The best chain should have at least this much work.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000011f1db4843f05806");
|
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000050b6f9f1c2494ad8"); // 3,000,000
|
||||||
|
|
||||||
// By default assume that the signatures in ancestors of this block are valid.
|
// By default assume that the signatures in ancestors of this block are valid.
|
||||||
consensus.defaultAssumeValid = uint256S("0x4a8cb5ca397b7c92c270ccfa9139ffb93f7c5b9515e52486c635c7a1dee9d221"); // 2000000
|
consensus.defaultAssumeValid = uint256S("0x5ad3a302e3b1c681f0177411384ea03ee595a80a530c23a61f22839fae948e7f"); // 3,000,000
|
||||||
|
|
||||||
// Difficulty adjustments
|
// Difficulty adjustments
|
||||||
consensus.nPowTargetSpacing = 40; // 40s block time
|
consensus.nPowTargetSpacing = 40; // 40s block time
|
||||||
@ -139,6 +139,7 @@ public:
|
|||||||
pchMessageStart[3] = 0xf1;
|
pchMessageStart[3] = 0xf1;
|
||||||
nDefaultPort = 7312;
|
nDefaultPort = 7312;
|
||||||
nPruneAfterHeight = 100000;
|
nPruneAfterHeight = 100000;
|
||||||
|
nNlrLimit = 100; // 100 * ~40s = ~66 minutes
|
||||||
|
|
||||||
genesis = CreateGenesisBlock(1371488396, 1000112548, 0x1e0ffff0, 1, 100 * COIN);
|
genesis = CreateGenesisBlock(1371488396, 1000112548, 0x1e0ffff0, 1, 100 * COIN);
|
||||||
consensus.hashGenesisBlock = genesis.GetHash();
|
consensus.hashGenesisBlock = genesis.GetHash();
|
||||||
@ -191,15 +192,16 @@ public:
|
|||||||
{1796633, uint256S("0xc2da8b936a7f2c0de02aa0c6c45f3d971ebad78655255a945b0e60b62f27d445")},
|
{1796633, uint256S("0xc2da8b936a7f2c0de02aa0c6c45f3d971ebad78655255a945b0e60b62f27d445")},
|
||||||
{2094558, uint256S("0x946616c88286f32bfac15868456d87a86f8611e1f9b56594b81e46831ce43f81")},
|
{2094558, uint256S("0x946616c88286f32bfac15868456d87a86f8611e1f9b56594b81e46831ce43f81")},
|
||||||
{2532181, uint256S("0xcacd5149aaed1088ae1db997a741210b0525e941356104120f182f3159931c79")},
|
{2532181, uint256S("0xcacd5149aaed1088ae1db997a741210b0525e941356104120f182f3159931c79")},
|
||||||
|
{3000000, uint256S("0x5ad3a302e3b1c681f0177411384ea03ee595a80a530c23a61f22839fae948e7f")},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
chainTxData = ChainTxData{
|
chainTxData = ChainTxData{
|
||||||
// Data as of block cacd5149aaed1088ae1db997a741210b0525e941356104120f182f3159931c79 (height 2532181).
|
// Data as of block 5ad3a302e3b1c681f0177411384ea03ee595a80a530c23a61f22839fae948e7f (height 3,000,000).
|
||||||
1515282818, // * UNIX timestamp of last known number of transactions
|
1538389345, // * UNIX timestamp of last known number of transactions
|
||||||
3223208, // * total number of transactions between genesis and that timestamp
|
4563023, // * total number of transactions between genesis and that timestamp
|
||||||
// (the tx=... number in the SetBestChain debug.log lines)
|
// (the tx=... number in the SetBestChain debug.log lines)
|
||||||
0.04 // * estimated number of transactions per second after that timestamp
|
0.03 // * estimated number of transactions per second after that timestamp
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -237,10 +239,10 @@ public:
|
|||||||
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1530446401; // July 1, 2018 FLO future date
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1530446401; // July 1, 2018 FLO future date
|
||||||
|
|
||||||
// The best chain should have at least this much work.
|
// The best chain should have at least this much work.
|
||||||
consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000083540886d");
|
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000003dd47d3172"); // 230,000
|
||||||
|
|
||||||
// By default assume that the signatures in ancestors of this block are valid.
|
// By default assume that the signatures in ancestors of this block are valid.
|
||||||
consensus.defaultAssumeValid = uint256S("0x4be79531ee8b0f410f0d8c8d785083acb4e14e5d54b0820502bc60f98a629b19"); //flo testnet block 20,000
|
consensus.defaultAssumeValid = uint256S("0xc2e6451240a580c3bfa5ddbfad1b001f8655e7c51d5c32c123e16f69c2d2b539"); // 230,000
|
||||||
|
|
||||||
// Difficulty adjustments
|
// Difficulty adjustments
|
||||||
consensus.nPowTargetSpacing = 40; // 40s block time
|
consensus.nPowTargetSpacing = 40; // 40s block time
|
||||||
@ -274,6 +276,7 @@ public:
|
|||||||
pchMessageStart[3] = 0xf2;
|
pchMessageStart[3] = 0xf2;
|
||||||
nDefaultPort = 17312;
|
nDefaultPort = 17312;
|
||||||
nPruneAfterHeight = 100000;
|
nPruneAfterHeight = 100000;
|
||||||
|
nNlrLimit = 50; // 50 * ~40s = ~33 minutes
|
||||||
|
|
||||||
genesis = CreateGenesisBlock(1371387277, 1000580675, 0x1e0ffff0, 1, 100 * COIN);
|
genesis = CreateGenesisBlock(1371387277, 1000580675, 0x1e0ffff0, 1, 100 * COIN);
|
||||||
consensus.hashGenesisBlock = genesis.GetHash();
|
consensus.hashGenesisBlock = genesis.GetHash();
|
||||||
@ -303,14 +306,15 @@ public:
|
|||||||
checkpointData = (CCheckpointData) {
|
checkpointData = (CCheckpointData) {
|
||||||
{
|
{
|
||||||
{2056, uint256S("0xd3334db071731beaa651f10624c2fea1a5e8c6f9e50f0e602f86262938374148")},
|
{2056, uint256S("0xd3334db071731beaa651f10624c2fea1a5e8c6f9e50f0e602f86262938374148")},
|
||||||
|
{230000, uint256S("0xc2e6451240a580c3bfa5ddbfad1b001f8655e7c51d5c32c123e16f69c2d2b539")},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
chainTxData = ChainTxData{
|
chainTxData = ChainTxData{
|
||||||
// flo: Data as of block 4be79531ee8b0f410f0d8c8d785083acb4e14e5d54b0820502bc60f98a629b19 (height 20000)
|
// flo: Data as of block c2e6451240a580c3bfa5ddbfad1b001f8655e7c51d5c32c123e16f69c2d2b539 (height 230,000)
|
||||||
1515699893, // * UNIX timestamp of last known number of transactions
|
1538135261, // * UNIX timestamp of last known number of transactions
|
||||||
34572, // * total number of transactions between genesis and that timestamp
|
265211, // * total number of transactions between genesis and that timestamp
|
||||||
0.001454897737891917 // * estimated number of transactions per second after that timestamp
|
0.01 // * estimated number of transactions per second after that timestamp
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -387,6 +391,7 @@ public:
|
|||||||
pchMessageStart[3] = 0xda;
|
pchMessageStart[3] = 0xda;
|
||||||
nDefaultPort = 17412;
|
nDefaultPort = 17412;
|
||||||
nPruneAfterHeight = 1000;
|
nPruneAfterHeight = 1000;
|
||||||
|
nNlrLimit = 10;
|
||||||
|
|
||||||
genesis = CreateGenesisBlock(1371387277, 0, 0x207fffff, 1, 100 * COIN);
|
genesis = CreateGenesisBlock(1371387277, 0, 0x207fffff, 1, 100 * COIN);
|
||||||
consensus.hashGenesisBlock = genesis.GetHash();
|
consensus.hashGenesisBlock = genesis.GetHash();
|
||||||
|
|||||||
@ -63,6 +63,7 @@ public:
|
|||||||
const Consensus::Params& GetConsensus() const { return consensus; }
|
const Consensus::Params& GetConsensus() const { return consensus; }
|
||||||
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
|
||||||
int GetDefaultPort() const { return nDefaultPort; }
|
int GetDefaultPort() const { return nDefaultPort; }
|
||||||
|
int NoLargeReorgLimit() const { return nNlrLimit; }
|
||||||
|
|
||||||
const CBlock& GenesisBlock() const { return genesis; }
|
const CBlock& GenesisBlock() const { return genesis; }
|
||||||
/** Default value for -checkmempool and -checkblockindex argument */
|
/** Default value for -checkmempool and -checkblockindex argument */
|
||||||
@ -87,6 +88,7 @@ protected:
|
|||||||
CMessageHeader::MessageStartChars pchMessageStart;
|
CMessageHeader::MessageStartChars pchMessageStart;
|
||||||
int nDefaultPort;
|
int nDefaultPort;
|
||||||
uint64_t nPruneAfterHeight;
|
uint64_t nPruneAfterHeight;
|
||||||
|
int nNlrLimit;
|
||||||
std::vector<CDNSSeedData> vSeeds;
|
std::vector<CDNSSeedData> vSeeds;
|
||||||
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
|
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
|
||||||
std::string strNetworkID;
|
std::string strNetworkID;
|
||||||
|
|||||||
@ -70,9 +70,9 @@ struct Params {
|
|||||||
return nTargetTimespan_Version1;
|
return nTargetTimespan_Version1;
|
||||||
// V2
|
// V2
|
||||||
if (height < nHeight_Difficulty_Version3)
|
if (height < nHeight_Difficulty_Version3)
|
||||||
return nInterval_Version2 * nPowTargetSpacing;
|
return nAveragingInterval_Version2 * nPowTargetSpacing;
|
||||||
// V3
|
// V3
|
||||||
return nInterval_Version3 * nPowTargetSpacing;
|
return nAveragingInterval_Version3 * nPowTargetSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t DifficultyAdjustmentInterval(int height) const {
|
int64_t DifficultyAdjustmentInterval(int height) const {
|
||||||
|
|||||||
@ -157,7 +157,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
|
|||||||
return nSigOps;
|
return nSigOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
|
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||||
{
|
{
|
||||||
// Basic checks that don't depend on any context
|
// Basic checks that don't depend on any context
|
||||||
if (tx.vin.empty())
|
if (tx.vin.empty())
|
||||||
@ -181,14 +181,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
|
|||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
|
// Check for duplicate inputs - note that this check is slow (no longer skipped due to CVE-2018-17144)
|
||||||
if (fCheckDuplicateInputs) {
|
std::set<COutPoint> vInOutPoints;
|
||||||
std::set<COutPoint> vInOutPoints;
|
for (const auto& txin : tx.vin)
|
||||||
for (const auto& txin : tx.vin)
|
{
|
||||||
{
|
if (!vInOutPoints.insert(txin.prevout).second)
|
||||||
if (!vInOutPoints.insert(txin.prevout).second)
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class CValidationState;
|
|||||||
/** Transaction validation functions */
|
/** Transaction validation functions */
|
||||||
|
|
||||||
/** Context-independent validity checks */
|
/** Context-independent validity checks */
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
|
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -401,6 +401,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
|
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER));
|
||||||
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
|
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXSENDBUFFER));
|
||||||
strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
|
strUsage += HelpMessageOpt("-maxtimeadjustment", strprintf(_("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)"), DEFAULT_MAX_TIME_ADJUSTMENT));
|
||||||
|
strUsage += HelpMessageOpt("-nlrlimit=<n>", strprintf(_("Set the limit to be considered a large reorg, -nlrlimit=0 to disable NLR mode (default: %u)"), defaultChainParams->NoLargeReorgLimit()));
|
||||||
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
|
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
|
||||||
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
|
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
|
||||||
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
|
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
|
||||||
|
|||||||
@ -85,7 +85,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
|
|||||||
if (fShift)
|
if (fShift)
|
||||||
bnNew >>= 1;
|
bnNew >>= 1;
|
||||||
bnNew *= nActualTimespan;
|
bnNew *= nActualTimespan;
|
||||||
bnNew /= params.AveragingInterval(pindexLast->nHeight+1) * params.nPowTargetSpacing;
|
bnNew /= params.TargetTimespan(pindexLast->nHeight+1);
|
||||||
if (fShift)
|
if (fShift)
|
||||||
bnNew <<= 1;
|
bnNew <<= 1;
|
||||||
|
|
||||||
|
|||||||
@ -23,9 +23,9 @@
|
|||||||
|
|
||||||
static const uint64_t GB_BYTES = 1000000000LL;
|
static const uint64_t GB_BYTES = 1000000000LL;
|
||||||
/* Minimum free space (in GB) needed for data directory */
|
/* Minimum free space (in GB) needed for data directory */
|
||||||
static const uint64_t BLOCK_CHAIN_SIZE = 20;
|
static const uint64_t BLOCK_CHAIN_SIZE = 4;
|
||||||
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
|
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
|
||||||
static const uint64_t CHAIN_STATE_SIZE = 3;
|
static const uint64_t CHAIN_STATE_SIZE = 1;
|
||||||
/* Total required space (in GB) depending on user choice (prune, not prune) */
|
/* Total required space (in GB) depending on user choice (prune, not prune) */
|
||||||
static uint64_t requiredSpace;
|
static uint64_t requiredSpace;
|
||||||
|
|
||||||
@ -127,8 +127,8 @@ Intro::Intro(QWidget *parent) :
|
|||||||
ui->lblExplanation1->setText(ui->lblExplanation1->text()
|
ui->lblExplanation1->setText(ui->lblExplanation1->text()
|
||||||
.arg(tr(PACKAGE_NAME))
|
.arg(tr(PACKAGE_NAME))
|
||||||
.arg(BLOCK_CHAIN_SIZE)
|
.arg(BLOCK_CHAIN_SIZE)
|
||||||
.arg(2009)
|
.arg(2013)
|
||||||
.arg(tr("Bitcoin"))
|
.arg(tr("Flo"))
|
||||||
);
|
);
|
||||||
ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
|
ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ Intro::Intro(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
requiredSpace += CHAIN_STATE_SIZE;
|
requiredSpace += CHAIN_STATE_SIZE;
|
||||||
ui->sizeWarningLabel->setText(
|
ui->sizeWarningLabel->setText(
|
||||||
tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
|
tr("%1 will download and store a copy of the Flo block chain.").arg(tr(PACKAGE_NAME)) + " " +
|
||||||
storageRequiresMsg.arg(requiredSpace) + " " +
|
storageRequiresMsg.arg(requiredSpace) + " " +
|
||||||
tr("The wallet will also be stored in this directory.")
|
tr("The wallet will also be stored in this directory.")
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1457,7 +1457,7 @@ UniValue reconsiderblock(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
ActivateBestChain(state, Params());
|
ActivateBestChain(state, Params(), std::shared_ptr<const CBlock>(), true);
|
||||||
|
|
||||||
if (!state.IsValid()) {
|
if (!state.IsValid()) {
|
||||||
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
|
||||||
|
|||||||
@ -2313,12 +2313,42 @@ static void PruneBlockIndexCandidates() {
|
|||||||
* Try to make some progress towards making pindexMostWork the active block.
|
* Try to make some progress towards making pindexMostWork the active block.
|
||||||
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
|
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
|
||||||
*/
|
*/
|
||||||
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace, bool reconsider)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||||
|
|
||||||
|
int nNlrLimit = gArgs.GetArg("-nlrlimit", Params().NoLargeReorgLimit());
|
||||||
|
if (nNlrLimit != 0 && !reconsider && !IsInitialBlockDownload() && pindexFork != nullptr
|
||||||
|
&& chainActive.Tip()->nHeight - pindexFork->nHeight >= nNlrLimit) {
|
||||||
|
LogPrintf("%s: NLR triggered! current height=%d current hash=%s | fork height=%d fork hash=%s\n", __func__,
|
||||||
|
pindexOldTip->nHeight, pindexOldTip->GetBlockHash().ToString(), pindexMostWork->nHeight,
|
||||||
|
pindexMostWork->GetBlockHash().ToString());
|
||||||
|
CBlockIndex *pindexWalk = pindexMostWork;
|
||||||
|
|
||||||
|
// mark invalid_child from tip of fork to second block of fork
|
||||||
|
while (pindexWalk->nHeight != pindexFork->nHeight+2) {
|
||||||
|
pindexWalk = pindexWalk->pprev;
|
||||||
|
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
|
||||||
|
setDirtyBlockIndex.insert(pindexWalk);
|
||||||
|
setBlockIndexCandidates.erase(pindexWalk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark invalid first block of fork
|
||||||
|
pindexWalk = pindexWalk->pprev;
|
||||||
|
pindexWalk->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
setDirtyBlockIndex.insert(pindexWalk);
|
||||||
|
setBlockIndexCandidates.erase(pindexWalk);
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
assert(pindexWalk->pprev == pindexFork);
|
||||||
|
|
||||||
|
fInvalidFound = true;
|
||||||
|
InvalidChainFound(pindexMostWork);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Disconnect active blocks which are no longer in the best chain.
|
// Disconnect active blocks which are no longer in the best chain.
|
||||||
bool fBlocksDisconnected = false;
|
bool fBlocksDisconnected = false;
|
||||||
DisconnectedBlockTransactions disconnectpool;
|
DisconnectedBlockTransactions disconnectpool;
|
||||||
@ -2420,7 +2450,7 @@ static void NotifyHeaderTip() {
|
|||||||
* or an activated best chain. pblock is either nullptr or a pointer to a block
|
* or an activated best chain. pblock is either nullptr or a pointer to a block
|
||||||
* that is already loaded (to avoid loading it again from disk).
|
* that is already loaded (to avoid loading it again from disk).
|
||||||
*/
|
*/
|
||||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock, bool reconsider) {
|
||||||
// Note that while we're often called here from ProcessNewBlock, this is
|
// Note that while we're often called here from ProcessNewBlock, this is
|
||||||
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
||||||
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
||||||
@ -2451,7 +2481,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|||||||
|
|
||||||
bool fInvalidFound = false;
|
bool fInvalidFound = false;
|
||||||
std::shared_ptr<const CBlock> nullBlockPtr;
|
std::shared_ptr<const CBlock> nullBlockPtr;
|
||||||
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
|
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace, reconsider))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (fInvalidFound) {
|
if (fInvalidFound) {
|
||||||
@ -2824,7 +2854,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
|
|
||||||
// Check transactions
|
// Check transactions
|
||||||
for (const auto& tx : block.vtx)
|
for (const auto& tx : block.vtx)
|
||||||
if (!CheckTransaction(*tx, state, false))
|
if (!CheckTransaction(*tx, state))
|
||||||
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
|
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
|
||||||
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
||||||
|
|
||||||
|
|||||||
@ -273,7 +273,7 @@ bool IsInitialBlockDownload();
|
|||||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||||
bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
|
bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
|
||||||
/** Find the best known block, and make it the tip of the block chain */
|
/** Find the best known block, and make it the tip of the block chain */
|
||||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
|
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>(), bool reconsider=false);
|
||||||
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
|
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
|
||||||
|
|||||||
105
test/functional/nlr.py
Normal file
105
test/functional/nlr.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
|
# Copyright (c) Flo Developers 2013-2018
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
"""Test the getchaintips RPC.
|
||||||
|
|
||||||
|
- introduce a network split
|
||||||
|
- work on chains of different lengths
|
||||||
|
- join the network together again
|
||||||
|
- verify that getchaintips now returns two chain tips.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import assert_equal
|
||||||
|
|
||||||
|
class GetChainTipsTest (BitcoinTestFramework):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.num_nodes = 4
|
||||||
|
self.extra_args = [['-nlrlimit=0'], ['-nlrlimit=10'], ['-nlrlimit=10'], ['-nlrlimit=10']]
|
||||||
|
self.setup_clean_chain = False
|
||||||
|
|
||||||
|
def run_test (self):
|
||||||
|
|
||||||
|
tips = self.nodes[0].getchaintips ()
|
||||||
|
assert_equal (len (tips), 1)
|
||||||
|
assert_equal (tips[0]['branchlen'], 0)
|
||||||
|
assert_equal (tips[0]['height'], 200)
|
||||||
|
assert_equal (tips[0]['status'], 'active')
|
||||||
|
|
||||||
|
# Split the network and build two chains of different lengths.
|
||||||
|
self.split_network()
|
||||||
|
self.nodes[0].generate(10)
|
||||||
|
self.nodes[2].generate(20)
|
||||||
|
self.sync_all([self.nodes[:2], self.nodes[2:]])
|
||||||
|
|
||||||
|
tips = self.nodes[1].getchaintips ()
|
||||||
|
assert_equal (len (tips), 1)
|
||||||
|
shortTip = tips[0]
|
||||||
|
assert_equal(shortTip['branchlen'], 0)
|
||||||
|
assert_equal(shortTip['height'], 210)
|
||||||
|
assert_equal(tips[0]['status'], 'active')
|
||||||
|
|
||||||
|
tips = self.nodes[3].getchaintips ()
|
||||||
|
assert_equal (len (tips), 1)
|
||||||
|
longTip = tips[0]
|
||||||
|
assert_equal (longTip['branchlen'], 0)
|
||||||
|
assert_equal (longTip['height'], 220)
|
||||||
|
assert_equal (tips[0]['status'], 'active')
|
||||||
|
|
||||||
|
# Join the network halves and check that we now have two tips
|
||||||
|
# (at least at the nodes that previously had the short chain).
|
||||||
|
print("pre join")
|
||||||
|
self.join_network_no_sync ()
|
||||||
|
time.sleep(10)
|
||||||
|
print("post join")
|
||||||
|
|
||||||
|
print("node 0")
|
||||||
|
print(self.nodes[0].getchaintips())
|
||||||
|
print("node 1")
|
||||||
|
print(self.nodes[1].getchaintips())
|
||||||
|
print("node 2")
|
||||||
|
print(self.nodes[2].getchaintips())
|
||||||
|
|
||||||
|
print("reconsider")
|
||||||
|
self.nodes[1].reconsiderblock(self.nodes[2].getbestblockhash())
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
|
print("node 0")
|
||||||
|
print(self.nodes[0].getchaintips ())
|
||||||
|
print("node 1")
|
||||||
|
print(self.nodes[1].getchaintips ())
|
||||||
|
print("node 2")
|
||||||
|
print(self.nodes[2].getchaintips ())
|
||||||
|
self.nodes[2].generate(20)
|
||||||
|
|
||||||
|
self.sync_all()
|
||||||
|
self.nodes[1].generate(20)
|
||||||
|
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
|
print("node 0")
|
||||||
|
print(self.nodes[0].getchaintips ())
|
||||||
|
print("node 1")
|
||||||
|
print(self.nodes[1].getchaintips ())
|
||||||
|
print("node 2")
|
||||||
|
print(self.nodes[2].getchaintips ())
|
||||||
|
|
||||||
|
# tips = self.nodes[1].getchaintips ()
|
||||||
|
# assert_equal (len (tips), 2)
|
||||||
|
# assert_equal (tips[0], longTip)
|
||||||
|
#
|
||||||
|
# assert_equal (tips[1]['branchlen'], 10)
|
||||||
|
# assert_equal (tips[1]['status'], 'valid-fork')
|
||||||
|
# tips[1]['branchlen'] = 0
|
||||||
|
# tips[1]['status'] = 'active'
|
||||||
|
# assert_equal (tips[1], shortTip)
|
||||||
|
|
||||||
|
assert_equal(1, 3)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
GetChainTipsTest().main()
|
||||||
@ -310,6 +310,12 @@ class BitcoinTestFramework(object):
|
|||||||
connect_nodes_bi(self.nodes, 1, 2)
|
connect_nodes_bi(self.nodes, 1, 2)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
|
def join_network_no_sync(self):
|
||||||
|
"""
|
||||||
|
Join the (previously split) network halves together. Do not wait sync.
|
||||||
|
"""
|
||||||
|
connect_nodes_bi(self.nodes, 1, 2)
|
||||||
|
|
||||||
def sync_all(self, node_groups=None):
|
def sync_all(self, node_groups=None):
|
||||||
if not node_groups:
|
if not node_groups:
|
||||||
node_groups = [self.nodes]
|
node_groups = [self.nodes]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user