Compare commits

...

25 Commits

Author SHA1 Message Date
Duke Leto a95c8965d2 Merge branch 'duke' into danger 3 years ago
Duke Leto ec53bba953 Merge branch 'dev' into duke 3 years ago
Duke Leto 23616274eb Merge branch 'master' into dev 3 years ago
Duke Leto 8056c2916a Merge branch 'dev' into danger 3 years ago
Duke Leto 7647ff3dea Report work queue depth in errors and increase default rpcthreads to 8 3 years ago
Duke Leto 1157d74d4b Merge branch 'master' into dev 3 years ago
Duke Leto 532f46d55f Merge branch 'dev' into danger 3 years ago
Duke Leto 82b39d89cf Merge branch 'dev' of https://git.hush.is/hush/hush3 into dev 3 years ago
Duke Leto 8339b55df4 Test-before-evict in addrman 3 years ago
Duke Leto dd1453422b Add some p2p CLI options 3 years ago
Duke Leto 8b6d2dc545 Merge pull request 'added help2man check in gen-manpages.sh' (#32) from jahway603/hush3:dev into dev 3 years ago
jahway603 4ca41a1357 added help2man check in gen-manpages.sh 3 years ago
Duke Leto ea2b68c1d3 Feeler connections ported from BTC core, eclipse attack mitigation 3 years ago
Duke Leto cadab16cdb Revert "Shitty VPS limiting disk i/o should not crash a full node..." 3 years ago
Duke Leto bb31926051 Merge branch 'master' into danger 3 years ago
Duke Leto e76dccdb2c Merge branch 'dev' into duke 3 years ago
Duke Leto dbef6b34c8 Merge remote-tracking branch 'origin/master' into dev 3 years ago
Duke Leto 8ed3ced34f Log block height in AddToWallet 3 years ago
Duke Leto fd0d0e6c75 Remove unused partition check code 3 years ago
Duke Leto 3c03d271c2 Allowlisted peers are allowed to getheaders during IBD 3 years ago
Duke Leto f404fbf16a Merge branch 'dev' into duke 3 years ago
Duke Leto 3f30e4ec78 Merge branch 'dev' into danger 3 years ago
Duke Leto c90323865a Shitty VPS limiting disk i/o should not crash a full node... 3 years ago
Duke Leto 89085d44da Merge branch 'dev' into duke 3 years ago
Duke Leto 165b98df3d Show remaining blocks in BuildWitnessCache logging 4 years ago
  1. 11
      contrib/devtools/gen-manpages.sh
  2. 98
      src/addrman.cpp
  3. 57
      src/addrman.h
  4. 12
      src/httpserver.cpp
  5. 3
      src/httpserver.h
  6. 107
      src/main.cpp
  7. 3
      src/main.h
  8. 119
      src/net.cpp
  9. 14
      src/net.h
  10. 8
      src/rpc/rawtransaction.cpp
  11. 163
      src/test/addrman_tests.cpp
  12. 31
      src/test/netbase_tests.cpp
  13. 4
      src/wallet/wallet.cpp

11
contrib/devtools/gen-manpages.sh

@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (c) 2016-2020 The Hush developers
# Copyright (c) 2016-2021 The Hush developers
# Released under the GPLv3
TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
@ -12,6 +12,15 @@ HUSHTX=${HUSHTX:-$SRCDIR/hush-tx}
[ ! -x $HUSHD ] && echo "$HUSHD not found or not executable." && exit 1
# Check if help2man is installed
# If not then display error to user and exit
if ! command -v help2man &> /dev/null
then
echo "help2man could not be found"
echo "Please install from your Linux package manager and try again"
exit
fi
# use this if hushd is not running
#HUSHVER="v3.6.2"
HUSHVER=$(./src/hushd --version|head -n1|cut -d' ' -f4|cut -d- -f1)

98
src/addrman.cpp

@ -215,8 +215,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId)
info.fInTried = true;
}
void CAddrMan::Good_(const CService& addr, int64_t nTime)
{
void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime) {
int nId;
CAddrInfo* pinfo = Find(addr, &nId);
@ -258,12 +257,101 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime)
if (nUBucket == -1)
return;
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
// which tried bucket to move the entry to
int tried_bucket = info.GetTriedBucket(nKey,m_asmap);
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
// Will moving this address into tried evict another entry?
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
LogPrint("addrman", "Collision inserting element into tried table, moving %s to m_tried_collisions=%d\n", addr.ToString(), m_tried_collisions.size());
if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
m_tried_collisions.insert(nId);
}
} else {
LogPrint("addrman", "Moving %s to tried\n", addr.ToString());
printf("%s: Moving %s to tried\n", __func__, addr.ToString().c_str() );
// move nId to the tried tables
MakeTried(info, nId);
// move nId to the tried tables
MakeTried(info, nId);
}
}
void CAddrMan::ResolveCollisions_() {
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
int id_new = *it;
bool erase_collision = false;
// If id_new not found in mapInfo remove it from m_tried_collisions
if (mapInfo.count(id_new) != 1) {
erase_collision = true;
} else {
CAddrInfo& info_new = mapInfo[id_new];
// Which tried bucket to move the entry to.
int tried_bucket = info_new.GetTriedBucket(nKey,m_asmap);
int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
if (!info_new.IsValid()) { // id_new may no longer map to a valid address
erase_collision = true;
} else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
// Get the to-be-evicted address that is being tested
int id_old = vvTried[tried_bucket][tried_bucket_pos];
CAddrInfo& info_old = mapInfo[id_old];
// Has successfully connected in last X hours
if (GetTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
erase_collision = true;
} else if (GetTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
// Give address at least 60 seconds to successfully connect
if (GetTime() - info_old.nLastTry > 60) {
LogPrint("addrman", "Swapping %s for %s in tried table\n", info_new.ToString(), info_old.ToString());
// Replaces an existing address already in the tried table with the new address
Good_(info_new, false, GetTime());
erase_collision = true;
}
}
} else { // Collision is not actually a collision anymore
Good_(info_new, false, GetTime());
erase_collision = true;
}
}
if (erase_collision) {
m_tried_collisions.erase(it++);
} else {
it++;
}
}
}
CAddrInfo CAddrMan::SelectTriedCollision_() {
if (m_tried_collisions.size() == 0) return CAddrInfo();
std::set<int>::iterator it = m_tried_collisions.begin();
// Selects a random element from m_tried_collisions
std::advance(it, GetRandInt(m_tried_collisions.size()));
int id_new = *it;
// If id_new not found in mapInfo remove it from m_tried_collisions
if (mapInfo.count(id_new) != 1) {
m_tried_collisions.erase(it);
return CAddrInfo();
}
CAddrInfo& newInfo = mapInfo[id_new];
// which tried bucket to move the entry to
int tried_bucket = newInfo.GetTriedBucket(nKey,m_asmap);
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
int id_old = vvTried[tried_bucket][tried_bucket_pos];
return mapInfo[id_old];
}
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
{
if (!addr.IsRoutable())

57
src/addrman.h

@ -1,8 +1,7 @@
// Copyright (c) 2012 Pieter Wuille
// Copyright (c) 2016-2020 The Hush developers
// Copyright (c) 2016-2021 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
@ -31,7 +30,6 @@
#include "clientversion.h"
#include "hash.h"
#include "netbase.h"
#include <map>
#include <set>
#include <stdint.h>
@ -43,7 +41,6 @@
class CAddrInfo : public CAddress
{
public:
//! last try whatsoever by us (memory only)
int64_t nLastTry;
@ -174,12 +171,18 @@ public:
//! after how many failed attempts we give up on a new node
#define ADDRMAN_RETRIES 3
//! the maximum number of tried addr collisions to store
#define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
//! how many successive failures are allowed ...
#define ADDRMAN_MAX_FAILURES 10
//! ... in at least this many days
#define ADDRMAN_MIN_FAIL_DAYS 7
//! how recent a successful connection should be before we allow an address to be evicted from tried
#define ADDRMAN_REPLACEMENT_HOURS 4
//! the maximum percentage of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX_PCT 23
@ -220,6 +223,12 @@ private:
//! list of "new" buckets
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
//! last time Good was called (memory only)
int64_t nLastGood;
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discpline used to resolve these collisions.
std::set<int> m_tried_collisions;
protected:
//! secret key to randomize bucket select with
uint256 nKey;
@ -244,7 +253,14 @@ protected:
void ClearNew(int nUBucket, int nUBucketPos);
//! Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64_t nTime);
void Good_(const CService &addr, bool test_before_evict, int64_t time);
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions_();
//! Return a random to-be-evicted tried table address.
CAddrInfo SelectTriedCollision_();
//! Add an entry to the "new" table.
bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
@ -583,12 +599,12 @@ public:
}
//! Mark an entry as accessible.
void Good(const CService &addr, int64_t nTime = GetTime())
void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetTime())
{
{
LOCK(cs);
Check();
Good_(addr, nTime);
Good_(addr, test_before_evict, nTime);
Check();
}
}
@ -604,9 +620,30 @@ public:
}
}
/**
* Choose an address to connect to.
*/
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions()
{
LOCK(cs);
Check();
ResolveCollisions_();
Check();
}
//! Randomly select an address in tried that another address is attempting to evict.
CAddrInfo SelectTriedCollision()
{
CAddrInfo ret;
{
LOCK(cs);
Check();
ret = SelectTriedCollision_();
Check();
}
return ret;
}
// Choose an address to connect to.
CAddrInfo Select(bool newOnly = false)
{
CAddrInfo addrRet;

12
src/httpserver.cpp

@ -1,9 +1,9 @@
// Copyright (c) 2015 The Bitcoin Core developers
// Copyright (c) 2016-2021 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
#include "httpserver.h"
#include "chainparamsbase.h"
#include "compat.h"
#include "util.h"
@ -12,15 +12,12 @@
#include "sync.h"
#include "ui_interface.h"
#include "utilstrencodings.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/thread.h>
@ -292,10 +289,11 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
if (i != iend) {
std::unique_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
assert(workQueue);
if (workQueue->Enqueue(item.get()))
if (workQueue->Enqueue(item.get())) {
item.release(); /* if true, queue took ownership */
else
item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
} else {
item->req->WriteReply(HTTP_INTERNAL, strprintf("Work queue depth %d exceeded", workQueue->Depth() ));
}
} else {
hreq->WriteReply(HTTP_NOTFOUND);
}

3
src/httpserver.h

@ -1,4 +1,5 @@
// Copyright (c) 2015 The Bitcoin Core developers
// Copyright (c) 2016-2021 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
@ -14,7 +15,7 @@
#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
static const int DEFAULT_HTTP_THREADS=4;
static const int DEFAULT_HTTP_THREADS=8;
static const int DEFAULT_HTTP_WORKQUEUE=16;
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;

107
src/main.cpp

@ -3043,77 +3043,12 @@ void ThreadScriptCheck() {
scriptcheckqueue.Thread();
}
//
// Called periodically asynchronously; alerts if it smells like
// we're being fed a bad chain (blocks being generated much
// too slowly or too quickly).
//
void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader,
int64_t nPowTargetSpacing)
{
if (bestHeader == NULL || initialDownloadCheck()) return;
static int64_t lastAlertTime = 0;
int64_t now = GetTime();
if (lastAlertTime > now-60*60*24) return; // Alert at most once per day
const int SPAN_HOURS=4;
const int SPAN_SECONDS=SPAN_HOURS*60*60;
int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing;
boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED);
std::string strWarning;
int64_t startTime = GetTime()-SPAN_SECONDS;
LOCK(cs);
const CBlockIndex* i = bestHeader;
int nBlocks = 0;
while (i->GetBlockTime() >= startTime) {
++nBlocks;
i = i->pprev;
if (i == NULL) return; // Ran out of chain, we must not be fully synced
}
// How likely is it to find that many by chance?
double p = boost::math::pdf(poisson, nBlocks);
LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS);
LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p);
// Aim for one false-positive about every fifty years of normal running:
const int FIFTY_YEARS = 50*365*24*60*60;
double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS);
if (bestHeader->GetHeight() > BLOCKS_EXPECTED)
{
if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED)
{
// Many fewer blocks than expected: alert!
strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"),
nBlocks, SPAN_HOURS, BLOCKS_EXPECTED);
}
else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED)
{
// Many more blocks than expected: alert!
strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"),
nBlocks, SPAN_HOURS, BLOCKS_EXPECTED);
}
}
if (!strWarning.empty())
{
strMiscWarning = strWarning;
CAlert::Notify(strWarning, true);
lastAlertTime = now;
}
}
static int64_t nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
static int64_t nTimeTotal = 0;
bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false);
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos);
@ -6845,10 +6780,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
//fprintf(stderr,"netmsg: %s\n", strCommand.c_str());
fprintf(stderr,"%s: netmsg: %s from %s\n", __func__, strCommand.c_str(), pfrom->addr.ToString().c_str() );
if (strCommand == "version") {
// Feeler connections exist only to verify if node is online
if (pfrom->fFeeler) {
assert(pfrom->fInbound == false);
pfrom->fDisconnect = true;
fprintf(stderr,"%s: disconnecting feelerconn from %s\n", __func__, pfrom->addr.ToString().c_str() );
}
if (strCommand == "version")
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@ -6961,15 +6902,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
// Do Not Relay alerts
/*
{
LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom);
}
*/
pfrom->fSuccessfullyConnected = true;
string remoteAddr;
@ -7327,10 +7259,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
if (chainActive.LastTip() != 0 && chainActive.LastTip()->GetHeight() > 100000 && IsInitialBlockDownload())
{
//fprintf(stderr,"dont process getheaders during initial download\n");
return true;
if (chainActive.LastTip() != 0 && chainActive.LastTip()->GetHeight() > 100000 && IsInitialBlockDownload()) {
if(pfrom->fAllowlisted) {
LogPrint("net", "Allowing getheaders from allowlisted peer=%d during initial block download\n", pfrom->id);
} else {
LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id);
//fprintf(stderr,"dont process getheaders during initial download\n");
return true;
}
}
CBlockIndex* pindex = NULL;
if (locator.IsNull())

3
src/main.h

@ -239,8 +239,7 @@ bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */
void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Check if the daemon is in sync, if not, it returns 1 or if due to best header only, the difference in best

119
src/net.cpp

@ -62,6 +62,9 @@ using namespace hush;
#endif
#endif
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
#define USE_TLS "encrypted as fuck"
#if defined(USE_TLS) && !defined(TLS1_3_VERSION)
@ -73,9 +76,9 @@ using namespace hush;
using namespace std;
namespace {
//TODO: Make these CLI args
const int MAX_OUTBOUND_CONNECTIONS = 64;
const int MAX_INBOUND_FROMIP = 3;
int MAX_OUTBOUND_CONNECTIONS = GetArg("-maxoutboundconnections",64);
int MAX_FEELER_CONNECTIONS = GetArg("-maxfeelerconnections",1);
int MAX_INBOUND_FROMIP = GetArg("-maxinboundfromip",3);
struct ListenSocket {
SOCKET socket;
@ -1023,8 +1026,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
int nInbound = 0;
int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@ -1412,6 +1415,11 @@ void static ProcessOneShot()
}
}
int64_t PoissonNextSend(int64_t now, int average_interval_seconds)
{
return now + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
void ThreadOpenConnections()
{
// Connect to specific addresses
@ -1434,10 +1442,14 @@ void ThreadOpenConnections()
}
}
// Initiate network connections
int64_t nStart = GetTime();
while (true)
{
// Minimum time before next feeler connection (in microseconds).
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true) {
ProcessOneShot();
MilliSleep(500);
@ -1450,19 +1462,17 @@ void ThreadOpenConnections()
if (GetTime() - nStart > 60) {
static bool done = false;
if (!done) {
// skip DNS seeds for staked chains.
LogPrintf("Adding fixed seed nodes.\n");
addrman.Add(convertSeed6(Params().FixedSeeds()), CNetAddr("127.0.0.1"));
done = true;
}
}
// Choose an address to connect to based on most recently seen
CAddress addrConnect;
// Only connect out to one peer per network group (/16 for IPv4).
// Use -asmap for ASN bucketing
// Only connect out to one peer per network group. Originally /16 for IPv4, now ASNs via
// -asmap for ASN bucketing, which is enabled by default
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
set<vector<unsigned char> > setConnected;
@ -1475,13 +1485,46 @@ void ThreadOpenConnections()
}
}
}
assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));
// "Feeler Connections" as per https://eprint.iacr.org/2015/263.pdf
// "Eclipse Attacks on Bitcoin’s Peer-to-Peer Network" by
// Ethan Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg.
//
// Design goals:
// * Increase the number of connectable addresses in the tried table.
//
// Method:
// * Choose a random address from new and attempt to connect to it if we can connect
// successfully it is added to tried.
// * Start attempting feeler connections only after node finishes making outbound
// connections.
// * Make feeler connections randomly with 120s average interval via PoissonNextSend.
// Originally from https://github.com/bitcoin/bitcoin/pull/8282
// Modified for API changes by Duke Leto
bool fFeeler = false;
if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
fFeeler = true;
} else {
continue;
}
}
int64_t nANow = GetTime();
int64_t nNow = GetTime();
int nTries = 0;
int nTries = 0;
while (true)
{
CAddrInfo addr = addrman.Select();
addrman.ResolveCollisions();
while (true) {
CAddrInfo addr = addrman.SelectTriedCollision();
// SelectTriedCollision returns an invalid address if it is empty.
if (!fFeeler || !addr.IsValid()) {
addr = addrman.Select(fFeeler);
}
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup(addrman.m_asmap)) || IsLocal(addr))
@ -1498,9 +1541,16 @@ void ThreadOpenConnections()
continue;
// only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30)
if (nNow - addr.nLastTry < 600 && nTries < 30)
continue;
/* TODO: port this code
// only consider nodes missing relevant services after 40 failed attempts
if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
continue;
*/
//TODO: why is this a good thing?
// do not allow non-default ports, unless after 50 invalid addresses selected already
if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50)
continue;
@ -1509,8 +1559,18 @@ void ThreadOpenConnections()
break;
}
if (addrConnect.IsValid())
OpenNetworkConnection(addrConnect, &grant);
if (addrConnect.IsValid()) {
if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
MilliSleep(randsleep);
LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString().c_str());
printf("%s: Making feeler connection to %s\n", __func__, addrConnect.ToString().c_str());
}
//int failures = setConnected.size() >= std::min(nMaxConnections - 1, 2);
OpenNetworkConnection(addrConnect,/*failures,*/ &grant, NULL, false, fFeeler);
}
}
}
@ -1591,7 +1651,7 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
bool OpenNetworkConnection(const CAddress& addrConnect, /* bool fCountFailure, */ CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{
// Initiate outbound network connection
boost::this_thread::interruption_point();
@ -1604,6 +1664,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
return false;
CNode* pnode = ConnectNode(addrConnect, pszDest);
//CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);
boost::this_thread::interruption_point();
if (!pnode)
@ -1611,8 +1672,11 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound);
pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;
return true;
}
@ -1858,7 +1922,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (semOutbound == NULL) {
// initialize semaphore
int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
int nMaxOutbound = min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}
@ -1907,7 +1971,7 @@ bool StopNode()
{
LogPrintf("StopNode()\n");
if (semOutbound)
for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();
if (HUSH_NSPV_FULLNODE && fAddressesInitialized)
@ -2166,12 +2230,13 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nTimeOffset = 0;
addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
nVersion = 0;
strSubVer = "";
fAllowlisted = false;
fOneShot = false;
fClient = false; // set by version message
fInbound = fInboundIn;
fOneShot = false;
fClient = false; // set by version message
fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
fDisconnect = false;

14
src/net.h

@ -82,10 +82,13 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 384;
/** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */
static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3;
/** Run the feeler connection loop once every 120 seconds. **/
static const int FEELER_INTERVAL = 120;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
int64_t PoissonNextSend(int64_t now, int average_interval_seconds);
void AddOneShot(const std::string& strDest);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
@ -93,7 +96,7 @@ CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fAllowlisted = false);
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
@ -220,7 +223,8 @@ public:
int nStartingHeight;
uint64_t nSendBytes;
uint64_t nRecvBytes;
bool fAllowlisted;
bool fAllowlisted; // If true this node bypasses DoS ban limits
bool fFeeler; // If true this node is being used as a short lived feeler.
double dPingTime;
double dPingWait;
std::string addrLocal;
@ -228,7 +232,7 @@ public:
CAddress addr;
// Bind address of our side of the connection
// CAddress addrBind; // https://github.com/bitcoin/bitcoin/commit/a7e3c2814c8e49197889a4679461be42254e5c51
uint32_t m_mapped_as;
uint32_t m_mapped_as; // Mapped ASN for this address
};
@ -273,9 +277,6 @@ public:
};
/** Information about a peer */
class CNode
{
@ -323,6 +324,7 @@ public:
bool fOneShot;
bool fClient;
bool fInbound;
bool fFeeler;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;

8
src/rpc/rawtransaction.cpp

@ -1,6 +1,6 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016-2020 The Hush developers
// Copyright (c) 2016-2021 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
/******************************************************************************
@ -1266,7 +1266,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m
if (fMissingInputs) {
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
}
throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
throw JSONRPCError(RPC_TRANSACTION_ERROR, strprintf("Invalid state: %s", state.GetRejectReason()));
}
}
} else if (fHaveChain) {
@ -1274,9 +1274,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m
}
LogPrintf("%s: Relaying raw tx to mempool\n", __FUNCTION__);
RelayTransaction(tx);
}
else
{
} else {
NSPV_broadcast((char *)params[0].get_str().c_str());
}
return hashTx.GetHex();

163
src/test/addrman_tests.cpp

@ -6,7 +6,6 @@
#include "test/test_bitcoin.h"
#include <string>
#include <boost/test/unit_test.hpp>
#include "hash.h"
#include "random.h"
@ -49,6 +48,17 @@ public:
{
CAddrMan::Delete(nId);
}
// Simulates connection failure so that we can test eviction of offline nodes
void SimConnFail(CService& addr)
{
int64_t nLastSuccess = 1;
Good_(addr, true, nLastSuccess); // Set last good connection in the deep past.
bool count_failure = false;
int64_t nLastTry = GetAdjustedTime()-61;
Attempt(addr, count_failure, nLastTry);
}
};
BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
@ -519,4 +529,155 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
// than 64 buckets.
BOOST_CHECK(buckets.size() > 64);
}
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
CAddrManTest addrman;
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1."+std::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
// No collisions yet.
BOOST_CHECK(addrman.size() == i);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
// Ensure Good handles duplicates well.
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1."+std::to_string(i));
addrman.Good(addr);
BOOST_CHECK(addrman.size() == 22);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
}
BOOST_AUTO_TEST_CASE(addrman_noevict)
{
CAddrManTest addrman;
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1."+std::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
// No collision yet.
BOOST_CHECK(addrman.size() == i);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
// Collision between 23 and 19.
CService addr23 = ResolveService("250.1.1.23");
addrman.Add(CAddress(addr23, NODE_NONE), source);
addrman.Good(addr23);
BOOST_CHECK(addrman.size() == 23);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.19:0");
// 23 should be discarded and 19 not evicted.
addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// Lets create two collisions.
for (unsigned int i = 24; i < 33; i++) {
CService addr = ResolveService("250.1.1."+std::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
BOOST_CHECK(addrman.size() == i);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
// Cause a collision.
CService addr33 = ResolveService("250.1.1.33");
addrman.Add(CAddress(addr33, NODE_NONE), source);
addrman.Good(addr33);
BOOST_CHECK(addrman.size() == 33);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.27:0");
// Cause a second collision.
addrman.Add(CAddress(addr23, NODE_NONE), source);
addrman.Good(addr23);
BOOST_CHECK(addrman.size() == 33);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() != "[::]:0");
addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
CAddrManTest addrman;
// Set addrman addr placement to be deterministic.
addrman.MakeDeterministic();
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1."+std::to_string(i));
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
// No collision yet.
BOOST_CHECK(addrman.size() == i);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
// Collision between 23 and 19.
CService addr = ResolveService("250.1.1.23");
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
BOOST_CHECK(addrman.size() == 23);
CAddrInfo info = addrman.SelectTriedCollision();
BOOST_CHECK(info.ToString() == "250.1.1.19:0");
// Ensure test of address fails, so that it is evicted.
addrman.SimConnFail(info);
// Should swap 23 for 19.
addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// If 23 was swapped for 19, then this should cause no collisions.
addrman.Add(CAddress(addr, NODE_NONE), source);
addrman.Good(addr);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
// If we insert 19 is should collide with 23.
CService addr19 = ResolveService("250.1.1.19");
addrman.Add(CAddress(addr19, NODE_NONE), source);
addrman.Good(addr19);
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.23:0");
addrman.ResolveCollisions();
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
}
BOOST_AUTO_TEST_SUITE_END()

31
src/test/netbase_tests.cpp

@ -5,9 +5,7 @@
#include "netbase.h"
#include "test/test_bitcoin.h"
#include <string>
#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
@ -24,6 +22,35 @@ BOOST_AUTO_TEST_CASE(netbase_networks)
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION);
}
/* TODO: port this feeler test
BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;
in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest = "";
bool fInboundIn = false;
// Test that fFeeler is false by default.
CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
*/
BOOST_AUTO_TEST_CASE(netbase_properties)
{
BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());

4
src/wallet/wallet.cpp

@ -1084,7 +1084,7 @@ void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly)
while (pblockindex) {
if (pblockindex->GetHeight() % 100 == 0 && pblockindex->GetHeight() < height - 5) {
LogPrintf("Building Witnesses for block %i %.4f complete\n", pblockindex->GetHeight(), pblockindex->GetHeight() / double(height));
LogPrintf("Building Witnesses for block %i %.4f complete, %d remaining\n", pblockindex->GetHeight(), pblockindex->GetHeight() / double(height), height - pblockindex->GetHeight() );
}
SaplingMerkleTree saplingTree;
@ -1473,7 +1473,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
}
//// debug print
LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
LogPrintf("AddToWallet %s at height %d %s%s\n", wtxIn.GetHash().ToString(), hush_blockheight(wtxIn.hashBlock), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)

Loading…
Cancel
Save