Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a671708f0b | |||
| be90d39cd4 | |||
| 4d0478add5 |
+1
-1
@@ -6,7 +6,7 @@ if(POLICY CMP0167)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(Triangles
|
project(Triangles
|
||||||
VERSION 5.8.2
|
VERSION 5.8.3
|
||||||
DESCRIPTION "Cryptographic Triangles Wallet"
|
DESCRIPTION "Cryptographic Triangles Wallet"
|
||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
)
|
)
|
||||||
|
|||||||
+165
-42
@@ -22,8 +22,10 @@
|
|||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -68,52 +70,170 @@ static bool RecvUntil(SOCKET sock, std::string& out, const std::string& delim)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Direct TCP connection bypassing Tor SOCKS proxy.
|
||||||
|
// Used for bootstrap downloads where the server is on clearnet.
|
||||||
|
static SOCKET ConnectDirectTCP(const std::string& host, int port, std::string& strError)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *result, *rp;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
std::string portStr = std::to_string(port);
|
||||||
|
int rc = getaddrinfo(host.c_str(), portStr.c_str(), &hints, &result);
|
||||||
|
if (rc != 0) {
|
||||||
|
strError = "DNS resolution failed for " + host;
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET hSocket = INVALID_SOCKET;
|
||||||
|
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||||
|
hSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if (hSocket == INVALID_SOCKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (connect(hSocket, rp->ai_addr, (int)rp->ai_addrlen) == 0)
|
||||||
|
break; // success
|
||||||
|
|
||||||
|
closesocket(hSocket);
|
||||||
|
hSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
|
if (hSocket == INVALID_SOCKET)
|
||||||
|
strError = "Cannot connect to " + host + ":" + portStr;
|
||||||
|
|
||||||
|
return hSocket;
|
||||||
|
}
|
||||||
|
|
||||||
bool DownloadFile(const std::string& host, const std::string& urlPath,
|
bool DownloadFile(const std::string& host, const std::string& urlPath,
|
||||||
const fs::path& destPath,
|
const fs::path& destPath,
|
||||||
ProgressCallback progressFn,
|
ProgressCallback progressFn,
|
||||||
std::string& strError)
|
std::string& strError,
|
||||||
|
bool noProxy)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Connect through Tor SOCKS proxy (ConnectSocketByName respects SetProxy)
|
std::string currentHost = host;
|
||||||
|
std::string currentPath = urlPath;
|
||||||
SOCKET hSocket = INVALID_SOCKET;
|
SOCKET hSocket = INVALID_SOCKET;
|
||||||
CService addr;
|
|
||||||
if (!ConnectSocketByName(addr, hSocket, host.c_str(), PORT, 30)) {
|
|
||||||
strError = "Cannot connect to " + host + " (check Tor proxy)";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send HTTP GET request
|
|
||||||
std::string request =
|
|
||||||
"GET " + urlPath + " HTTP/1.1\r\n"
|
|
||||||
"Host: " + host + "\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"User-Agent: Triangles\r\n"
|
|
||||||
"\r\n";
|
|
||||||
|
|
||||||
if (!SendAll(hSocket, request.data(), request.size())) {
|
|
||||||
closesocket(hSocket);
|
|
||||||
strError = "Failed to send request to " + host;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read response headers
|
|
||||||
std::string headerData;
|
std::string headerData;
|
||||||
if (!RecvUntil(hSocket, headerData, "\r\n\r\n")) {
|
int redirectCount = 0;
|
||||||
closesocket(hSocket);
|
const int MAX_REDIRECTS = 5;
|
||||||
strError = "Failed to read HTTP headers from " + host;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse status code from "HTTP/1.x NNN ..."
|
// Connection + redirect loop
|
||||||
unsigned int status_code = 0;
|
while (true) {
|
||||||
size_t sp = headerData.find(' ');
|
if (noProxy) {
|
||||||
if (sp != std::string::npos)
|
hSocket = ConnectDirectTCP(currentHost, PORT, strError);
|
||||||
status_code = atoi(headerData.c_str() + sp + 1);
|
if (hSocket == INVALID_SOCKET)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
CService addr;
|
||||||
|
if (!ConnectSocketByName(addr, hSocket, currentHost.c_str(), PORT, 30)) {
|
||||||
|
strError = "Cannot connect to " + currentHost + " (check Tor proxy)";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (status_code != 200) {
|
// Send HTTP GET request
|
||||||
closesocket(hSocket);
|
std::string request =
|
||||||
strError = "HTTP error " + std::to_string(status_code) + " for " + urlPath;
|
"GET " + currentPath + " HTTP/1.1\r\n"
|
||||||
return false;
|
"Host: " + currentHost + "\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"User-Agent: Triangles\r\n"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
if (!SendAll(hSocket, request.data(), request.size())) {
|
||||||
|
closesocket(hSocket);
|
||||||
|
strError = "Failed to send request to " + currentHost;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read response headers
|
||||||
|
if (!RecvUntil(hSocket, headerData, "\r\n\r\n")) {
|
||||||
|
closesocket(hSocket);
|
||||||
|
strError = "Failed to read HTTP headers from " + currentHost;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse status code from "HTTP/1.x NNN ..."
|
||||||
|
unsigned int status_code = 0;
|
||||||
|
size_t sp = headerData.find(' ');
|
||||||
|
if (sp != std::string::npos)
|
||||||
|
status_code = atoi(headerData.c_str() + sp + 1);
|
||||||
|
|
||||||
|
// Handle HTTP redirects
|
||||||
|
if (status_code == 301 || status_code == 302 ||
|
||||||
|
status_code == 307 || status_code == 308) {
|
||||||
|
closesocket(hSocket);
|
||||||
|
hSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
if (++redirectCount > MAX_REDIRECTS) {
|
||||||
|
strError = "Too many redirects for " + urlPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find Location header (case-insensitive)
|
||||||
|
std::string lowerHdr = headerData;
|
||||||
|
std::transform(lowerHdr.begin(), lowerHdr.end(),
|
||||||
|
lowerHdr.begin(), ::tolower);
|
||||||
|
size_t locPos = lowerHdr.find("\nlocation:");
|
||||||
|
if (locPos == std::string::npos) {
|
||||||
|
strError = "Redirect " + std::to_string(status_code) + " without Location header";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t valStart = locPos + 10; // skip "\nlocation:"
|
||||||
|
while (valStart < headerData.size() && headerData[valStart] == ' ')
|
||||||
|
valStart++;
|
||||||
|
size_t lineEnd = headerData.find("\r\n", valStart);
|
||||||
|
std::string location;
|
||||||
|
if (lineEnd != std::string::npos)
|
||||||
|
location = headerData.substr(valStart, lineEnd - valStart);
|
||||||
|
else
|
||||||
|
location = headerData.substr(valStart);
|
||||||
|
boost::trim(location);
|
||||||
|
|
||||||
|
// Reject HTTPS redirects (no TLS support)
|
||||||
|
if (location.compare(0, 8, "https://") == 0) {
|
||||||
|
strError = "Server redirected to HTTPS (not supported). "
|
||||||
|
"Configure bootstrap server for plain HTTP.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse redirect URL
|
||||||
|
if (location.compare(0, 7, "http://") == 0) {
|
||||||
|
std::string rest = location.substr(7);
|
||||||
|
size_t pathStart = rest.find('/');
|
||||||
|
if (pathStart != std::string::npos) {
|
||||||
|
currentHost = rest.substr(0, pathStart);
|
||||||
|
currentPath = rest.substr(pathStart);
|
||||||
|
} else {
|
||||||
|
currentHost = rest;
|
||||||
|
currentPath = "/";
|
||||||
|
}
|
||||||
|
// Strip port from host if present
|
||||||
|
size_t colonPos = currentHost.find(':');
|
||||||
|
if (colonPos != std::string::npos)
|
||||||
|
currentHost = currentHost.substr(0, colonPos);
|
||||||
|
} else if (!location.empty() && location[0] == '/') {
|
||||||
|
currentPath = location;
|
||||||
|
} else {
|
||||||
|
strError = "Unsupported redirect location: " + location;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Bootstrap: redirect %d -> %s%s\n",
|
||||||
|
status_code, currentHost.c_str(), currentPath.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status_code != 200) {
|
||||||
|
closesocket(hSocket);
|
||||||
|
strError = "HTTP error " + std::to_string(status_code) + " for " + currentPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break; // Got 200, proceed to download
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse Content-Length
|
// Parse Content-Length
|
||||||
@@ -183,13 +303,14 @@ bool DownloadFile(const std::string& host, const std::string& urlPath,
|
|||||||
|
|
||||||
bool FetchFileList(const std::string& host,
|
bool FetchFileList(const std::string& host,
|
||||||
std::vector<std::string>& files,
|
std::vector<std::string>& files,
|
||||||
std::string& strError)
|
std::string& strError,
|
||||||
|
bool noProxy)
|
||||||
{
|
{
|
||||||
// Download filelist.txt to a temp file
|
// Download filelist.txt to a temp file
|
||||||
fs::path tmpPath = fs::temp_directory_path() / "triangles_bootstrap_filelist.txt";
|
fs::path tmpPath = fs::temp_directory_path() / "triangles_bootstrap_filelist.txt";
|
||||||
|
|
||||||
std::string urlPath = std::string(BASE_PATH) + "filelist.txt";
|
std::string urlPath = std::string(BASE_PATH) + "filelist.txt";
|
||||||
if (!DownloadFile(host, urlPath, tmpPath, nullptr, strError))
|
if (!DownloadFile(host, urlPath, tmpPath, nullptr, strError, noProxy))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Read lines
|
// Read lines
|
||||||
@@ -458,10 +579,12 @@ bool DownloadBootstrap(const std::string& host,
|
|||||||
bool gotBlockFile = false;
|
bool gotBlockFile = false;
|
||||||
|
|
||||||
// Try downloading bootstrap.tar.gz first
|
// Try downloading bootstrap.tar.gz first
|
||||||
|
// Bootstrap server is on clearnet — bypass Tor proxy for DNS + HTTP
|
||||||
|
const bool noProxy = true;
|
||||||
fs::path tmpTarGz = dataDir / "bootstrap.tar.gz.tmp";
|
fs::path tmpTarGz = dataDir / "bootstrap.tar.gz.tmp";
|
||||||
std::string tarUrl = std::string(BASE_PATH) + "triangles-bootstrap.tar.gz";
|
std::string tarUrl = std::string(BASE_PATH) + "triangles-bootstrap.tar.gz";
|
||||||
|
|
||||||
bool tarDownloaded = DownloadFile(host, tarUrl, tmpTarGz, progressFn, strError);
|
bool tarDownloaded = DownloadFile(host, tarUrl, tmpTarGz, progressFn, strError, noProxy);
|
||||||
|
|
||||||
if (tarDownloaded) {
|
if (tarDownloaded) {
|
||||||
bool extractOk = ExtractTarGz(tmpTarGz, dataDir, strError);
|
bool extractOk = ExtractTarGz(tmpTarGz, dataDir, strError);
|
||||||
@@ -476,7 +599,7 @@ bool DownloadBootstrap(const std::string& host,
|
|||||||
// Fallback: try filelist.txt + individual file downloads
|
// Fallback: try filelist.txt + individual file downloads
|
||||||
std::string fallbackError;
|
std::string fallbackError;
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
if (!FetchFileList(host, files, fallbackError)) {
|
if (!FetchFileList(host, files, fallbackError, noProxy)) {
|
||||||
if (!tarDownloaded)
|
if (!tarDownloaded)
|
||||||
strError = strError + " (fallback also failed: " + fallbackError + ")";
|
strError = strError + " (fallback also failed: " + fallbackError + ")";
|
||||||
else
|
else
|
||||||
@@ -489,7 +612,7 @@ bool DownloadBootstrap(const std::string& host,
|
|||||||
fs::create_directories(destPath.parent_path());
|
fs::create_directories(destPath.parent_path());
|
||||||
|
|
||||||
std::string urlPath = std::string(BASE_PATH) + files[i];
|
std::string urlPath = std::string(BASE_PATH) + files[i];
|
||||||
if (!DownloadFile(host, urlPath, destPath, progressFn, strError))
|
if (!DownloadFile(host, urlPath, destPath, progressFn, strError, noProxy))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -22,16 +22,20 @@ namespace Bootstrap {
|
|||||||
// Check if data dir already has blockchain data
|
// Check if data dir already has blockchain data
|
||||||
bool NeedsBootstrap(const boost::filesystem::path& dataDir);
|
bool NeedsBootstrap(const boost::filesystem::path& dataDir);
|
||||||
|
|
||||||
// Download a single file via HTTP GET, write to destPath
|
// Download a single file via HTTP GET, write to destPath.
|
||||||
|
// If noProxy is true, bypass Tor SOCKS proxy and connect directly
|
||||||
|
// (used for clearnet bootstrap downloads).
|
||||||
bool DownloadFile(const std::string& host, const std::string& urlPath,
|
bool DownloadFile(const std::string& host, const std::string& urlPath,
|
||||||
const boost::filesystem::path& destPath,
|
const boost::filesystem::path& destPath,
|
||||||
ProgressCallback progressFn,
|
ProgressCallback progressFn,
|
||||||
std::string& strError);
|
std::string& strError,
|
||||||
|
bool noProxy = false);
|
||||||
|
|
||||||
// Fetch the file manifest (list of relative paths to download)
|
// Fetch the file manifest (list of relative paths to download)
|
||||||
bool FetchFileList(const std::string& host,
|
bool FetchFileList(const std::string& host,
|
||||||
std::vector<std::string>& files,
|
std::vector<std::string>& files,
|
||||||
std::string& strError);
|
std::string& strError,
|
||||||
|
bool noProxy = false);
|
||||||
|
|
||||||
// Download bootstrap.tar.gz and extract to dataDir.
|
// Download bootstrap.tar.gz and extract to dataDir.
|
||||||
// Falls back to filelist.txt + individual file download if tar.gz unavailable.
|
// Falls back to filelist.txt + individual file download if tar.gz unavailable.
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
||||||
#define CLIENT_VERSION_MAJOR 5
|
#define CLIENT_VERSION_MAJOR 5
|
||||||
#define CLIENT_VERSION_MINOR 8
|
#define CLIENT_VERSION_MINOR 8
|
||||||
#define CLIENT_VERSION_REVISION 2
|
#define CLIENT_VERSION_REVISION 3
|
||||||
#define CLIENT_VERSION_BUILD 0
|
#define CLIENT_VERSION_BUILD 0
|
||||||
|
|
||||||
// Converts the parameter X to a string after macro replacement on X has been performed.
|
// Converts the parameter X to a string after macro replacement on X has been performed.
|
||||||
|
|||||||
+25
-5
@@ -2970,15 +2970,15 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u
|
|||||||
// 2. Equal trust: deterministic hash tiebreaker — lower tip hash wins.
|
// 2. Equal trust: deterministic hash tiebreaker — lower tip hash wins.
|
||||||
// This ensures all nodes converge on the same chain even when two
|
// This ensures all nodes converge on the same chain even when two
|
||||||
// forks have identical cumulative difficulty (common in PoS).
|
// forks have identical cumulative difficulty (common in PoS).
|
||||||
// Rate-limited to one equal-trust reorg per 10 minutes to prevent
|
// Rate-limited to one equal-trust reorg per 2 minutes — short enough
|
||||||
// oscillation from Tor-latency-induced competing announcements.
|
// for fast convergence but long enough to prevent oscillation on Tor.
|
||||||
bool fNewBest = false;
|
bool fNewBest = false;
|
||||||
static int64_t nLastEqualTrustReorg = 0;
|
static int64_t nLastEqualTrustReorg = 0;
|
||||||
if (pindexNew->nChainTrust > nBestChainTrust)
|
if (pindexNew->nChainTrust > nBestChainTrust)
|
||||||
fNewBest = true;
|
fNewBest = true;
|
||||||
else if (pindexNew->nChainTrust == nBestChainTrust && pindexBest &&
|
else if (pindexNew->nChainTrust == nBestChainTrust && pindexBest &&
|
||||||
pindexNew->GetBlockHash() < pindexBest->GetBlockHash() &&
|
pindexNew->GetBlockHash() < pindexBest->GetBlockHash() &&
|
||||||
GetTime() - nLastEqualTrustReorg > 10 * 60)
|
GetTime() - nLastEqualTrustReorg > 2 * 60)
|
||||||
{
|
{
|
||||||
fNewBest = true;
|
fNewBest = true;
|
||||||
nLastEqualTrustReorg = GetTime();
|
nLastEqualTrustReorg = GetTime();
|
||||||
@@ -3190,14 +3190,20 @@ bool CBlock::AcceptBlock()
|
|||||||
if (!AddToBlockIndex(nFile, nBlockPos, hashProofOfStake))
|
if (!AddToBlockIndex(nFile, nBlockPos, hashProofOfStake))
|
||||||
return error("AcceptBlock() : AddToBlockIndex failed");
|
return error("AcceptBlock() : AddToBlockIndex failed");
|
||||||
|
|
||||||
// Relay inventory, but don't relay old inventory during initial block download
|
// Push new tip block directly to all peers. On a small Tor-only
|
||||||
|
// network the inv→getdata→block round-trip adds 1-2 seconds of latency
|
||||||
|
// per hop — enough for a competing staker to create a fork. Pushing
|
||||||
|
// the full block immediately cuts propagation to a single hop.
|
||||||
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
|
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
|
||||||
if (hashBestChain == hash)
|
if (hashBestChain == hash)
|
||||||
{
|
{
|
||||||
LOCK(cs_vNodes);
|
LOCK(cs_vNodes);
|
||||||
for (CNode* pnode : vNodes)
|
for (CNode* pnode : vNodes)
|
||||||
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
||||||
pnode->PushInventory(CInv(MSG_BLOCK, hash));
|
{
|
||||||
|
pnode->PushMessage("block", *this);
|
||||||
|
pnode->AddInventoryKnown(CInv(MSG_BLOCK, hash));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -5308,6 +5314,20 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||||||
pto->PushMessage("inv", vInv);
|
pto->PushMessage("inv", vInv);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Periodic chain-tip sync: every 45 seconds, ask each peer if they
|
||||||
|
// have blocks we don't. On a small Tor-only network, transient
|
||||||
|
// partitions can cause forks that persist silently — this ensures
|
||||||
|
// nodes discover the longer chain even without explicit announcement.
|
||||||
|
//
|
||||||
|
if (!IsInitialBlockDownload() && !pto->fClient && pindexBest &&
|
||||||
|
GetTime() - pto->nLastTipCheck > 45)
|
||||||
|
{
|
||||||
|
pto->nLastTipCheck = GetTime();
|
||||||
|
pto->pindexLastGetBlocksBegin = NULL; // reset dedup to force request
|
||||||
|
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Stall detection: if we're still catching up and no new blocks for
|
// Stall detection: if we're still catching up and no new blocks for
|
||||||
// a while, re-request. Active during IBD (5s timeout) and also
|
// a while, re-request. Active during IBD (5s timeout) and also
|
||||||
|
|||||||
+2
-2
@@ -59,10 +59,10 @@ static const int fHaveUPnP = false;
|
|||||||
|
|
||||||
static const uint256 hashGenesisBlockOfficial("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
static const uint256 hashGenesisBlockOfficial("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||||
static const uint256 hashGenesisBlockTestNet ("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
static const uint256 hashGenesisBlockTestNet ("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||||
inline int64_t GetMaxTimeDrift(int nHeight) { return (nHeight >= FORK_HEIGHT_V5_4) ? 3 * 60 : 10 * 60; }
|
inline int64_t GetMaxTimeDrift(int nHeight) { return (nHeight >= FORK_HEIGHT_V5_4) ? 90 : 10 * 60; }
|
||||||
inline int64_t PastDrift(int64_t nTime, int nHeight) { return nTime - GetMaxTimeDrift(nHeight); }
|
inline int64_t PastDrift(int64_t nTime, int nHeight) { return nTime - GetMaxTimeDrift(nHeight); }
|
||||||
inline int64_t FutureDrift(int64_t nTime, int nHeight) { return nTime + GetMaxTimeDrift(nHeight); }
|
inline int64_t FutureDrift(int64_t nTime, int nHeight) { return nTime + GetMaxTimeDrift(nHeight); }
|
||||||
// Height-less overloads always use post-V5.4 rules (3-min drift).
|
// Height-less overloads always use post-V5.4 rules (90-second drift).
|
||||||
// All nodes are well past FORK_HEIGHT_V5_4; using the global nBestHeight
|
// All nodes are well past FORK_HEIGHT_V5_4; using the global nBestHeight
|
||||||
// here previously caused nodes at different heights to disagree on block
|
// here previously caused nodes at different heights to disagree on block
|
||||||
// validity during the fork transition — a consensus-splitting bug.
|
// validity during the fork transition — a consensus-splitting bug.
|
||||||
|
|||||||
+1
-1
@@ -413,7 +413,7 @@ void StakeMiner(CWallet *pwallet)
|
|||||||
if (fTryToSync)
|
if (fTryToSync)
|
||||||
{
|
{
|
||||||
fTryToSync = false;
|
fTryToSync = false;
|
||||||
if (vNodes.size() < 1 || nBestHeight < GetNumBlocksOfPeers())
|
if (vNodes.size() < 2 || nBestHeight < GetNumBlocksOfPeers())
|
||||||
{
|
{
|
||||||
MilliSleep(60000);
|
MilliSleep(60000);
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ public:
|
|||||||
CBlockIndex* pindexLastGetHeadersBegin;
|
CBlockIndex* pindexLastGetHeadersBegin;
|
||||||
uint256 hashLastGetHeadersEnd;
|
uint256 hashLastGetHeadersEnd;
|
||||||
int nStartingHeight;
|
int nStartingHeight;
|
||||||
|
int64_t nLastTipCheck; // last time we asked this peer for chain tip
|
||||||
|
|
||||||
// flood relay
|
// flood relay
|
||||||
std::vector<CAddress> vAddrToSend;
|
std::vector<CAddress> vAddrToSend;
|
||||||
@@ -319,6 +320,7 @@ public:
|
|||||||
pindexLastGetHeadersBegin = 0;
|
pindexLastGetHeadersBegin = 0;
|
||||||
hashLastGetHeadersEnd = 0;
|
hashLastGetHeadersEnd = 0;
|
||||||
nStartingHeight = -1;
|
nStartingHeight = -1;
|
||||||
|
nLastTipCheck = 0;
|
||||||
fGetAddr = false;
|
fGetAddr = false;
|
||||||
nMisbehavior = 0;
|
nMisbehavior = 0;
|
||||||
hashCheckpointKnown = 0;
|
hashCheckpointKnown = 0;
|
||||||
|
|||||||
+1
-1
@@ -128,7 +128,7 @@ Value getstakinginfo(const Array& params, bool fHelp)
|
|||||||
|
|
||||||
// Add detailed diagnostics
|
// Add detailed diagnostics
|
||||||
obj.push_back(Pair("walletlocked", pwalletMain->IsLocked()));
|
obj.push_back(Pair("walletlocked", pwalletMain->IsLocked()));
|
||||||
obj.push_back(Pair("walletunlockedforstakingonly", pwalletMain->fWalletUnlockStakingOnly));
|
obj.push_back(Pair("walletunlockedforstakingonly", fWalletUnlockStakingOnly));
|
||||||
obj.push_back(Pair("connections", (int)vNodes.size()));
|
obj.push_back(Pair("connections", (int)vNodes.size()));
|
||||||
obj.push_back(Pair("initialblockdownload", IsInitialBlockDownload()));
|
obj.push_back(Pair("initialblockdownload", IsInitialBlockDownload()));
|
||||||
obj.push_back(Pair("maturecoins", nWeight > 0));
|
obj.push_back(Pair("maturecoins", nWeight > 0));
|
||||||
|
|||||||
Reference in New Issue
Block a user