Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a76d8049c0 | |||
| 0ce1558f54 | |||
| 2807f9a51c | |||
| 03a3423da0 | |||
| 12a011a9ff | |||
| 7a1afc7a95 | |||
| 262b4f2a2e | |||
| fadc5055b2 | |||
| 1c908c261d | |||
| 39216df8eb | |||
| ed59579a9d | |||
| 2aa7389c3f | |||
| 02970e2f8f | |||
| 2e00ac402a | |||
| c94dd46294 | |||
| df802c3b26 | |||
| 8430a506cc | |||
| 46a6196c92 |
@@ -5,6 +5,7 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
|
||||
timeout-minutes: 10
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
|
||||
strategy:
|
||||
@@ -51,6 +52,7 @@ jobs:
|
||||
|
||||
build-ubuntu-static-libs:
|
||||
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
@@ -115,6 +117,7 @@ jobs:
|
||||
|
||||
build-ubuntu-aarch64:
|
||||
|
||||
timeout-minutes: 10
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
|
||||
strategy:
|
||||
@@ -172,6 +175,7 @@ jobs:
|
||||
|
||||
build-windows-msys2:
|
||||
|
||||
timeout-minutes: 45
|
||||
runs-on: windows-latest
|
||||
|
||||
defaults:
|
||||
@@ -241,14 +245,16 @@ jobs:
|
||||
|
||||
build-windows-msbuild:
|
||||
|
||||
timeout-minutes: 20
|
||||
runs-on: windows-${{ matrix.config.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\", rx: "ON"}
|
||||
- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\", rx: "ON"}
|
||||
- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\", rx: "OFF"}
|
||||
- {vs: Visual Studio 16 2019, os: 2019, msbuild: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\amd64\\", rx: "OFF"}
|
||||
#- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\", rx: "ON"}
|
||||
#- {vs: Visual Studio 17 2022, os: 2022, msbuild: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Current\\Bin\\amd64\\", rx: "OFF"}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -287,6 +293,7 @@ jobs:
|
||||
|
||||
build-macos:
|
||||
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
@@ -353,7 +360,7 @@ jobs:
|
||||
|
||||
build-freebsd:
|
||||
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 75
|
||||
runs-on: ${{ matrix.os.host }}
|
||||
|
||||
strategy:
|
||||
@@ -410,3 +417,46 @@ jobs:
|
||||
with:
|
||||
name: p2pool-${{ matrix.os.name }}-${{ matrix.os.version }}
|
||||
path: build/p2pool
|
||||
|
||||
build-openbsd:
|
||||
|
||||
timeout-minutes: 75
|
||||
runs-on: ${{ matrix.os.host }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- name: openbsd
|
||||
architecture: x86-64
|
||||
version: '7.2'
|
||||
host: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Build p2pool
|
||||
uses: cross-platform-actions/action@v0.10.0
|
||||
with:
|
||||
operating_system: ${{ matrix.os.name }}
|
||||
architecture: ${{ matrix.os.architecture }}
|
||||
version: ${{ matrix.os.version }}
|
||||
shell: bash
|
||||
run: |
|
||||
sudo pkg_add -I cmake libuv zeromq curl
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make -j2
|
||||
cd ../tests
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make -j2
|
||||
./p2pool_tests
|
||||
|
||||
- name: Archive binary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: p2pool-${{ matrix.os.name }}-${{ matrix.os.version }}
|
||||
path: build/p2pool
|
||||
|
||||
@@ -20,6 +20,7 @@ on:
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
timeout-minutes: 20
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
|
||||
@@ -5,6 +5,7 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
cppcheck-ubuntu:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -31,6 +32,7 @@ jobs:
|
||||
|
||||
cppcheck-windows:
|
||||
|
||||
timeout-minutes: 20
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -22,6 +22,7 @@ env:
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
timeout-minutes: 15
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
|
||||
@@ -5,6 +5,7 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
sync-test-ubuntu:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
@@ -43,6 +44,7 @@ jobs:
|
||||
|
||||
sync-test-macos:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: macos-12
|
||||
|
||||
steps:
|
||||
@@ -78,6 +80,7 @@ jobs:
|
||||
|
||||
sync-test-windows:
|
||||
|
||||
timeout-minutes: 30
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
|
||||
@@ -4,6 +4,7 @@ project(p2pool)
|
||||
option(STATIC_BINARY "Build static binary" OFF)
|
||||
option(STATIC_LIBS "Link libuv and libzmq statically" OFF)
|
||||
option(WITH_RANDOMX "Include the RandomX library in the build. If this is turned off, p2pool will rely on monerod for verifying RandomX hashes" ON)
|
||||
option(WITH_LTO "Use link-time compiler optimization (if linking fails for you, run cmake with -DWITH_LTO=OFF)" ON)
|
||||
|
||||
option(DEV_TEST_SYNC "[Developer only] Sync test, stop p2pool after sync is complete" OFF)
|
||||
|
||||
|
||||
+16
-2
@@ -8,7 +8,15 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wcast-align -Wcast-qual -Wlogical-op -Wstrict-overflow=2 -Wundef -Wformat=2 -Wpointer-arith -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s -flto -fuse-linker-plugin")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
|
||||
if (WITH_LTO)
|
||||
set(OPTIMIZATION_FLAGS "${OPTIMIZATION_FLAGS} -flto -fuse-linker-plugin")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
|
||||
set(OPTIMIZATION_FLAGS "${OPTIMIZATION_FLAGS} -fno-associative-math")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
@@ -39,10 +47,16 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${GENERAL_FLAGS} ${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
set(GENERAL_FLAGS "-pthread")
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wno-undefined-internal -Wunreachable-code-aggressive -Wmissing-prototypes -Wmissing-variable-declarations -Werror")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants -flto")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
|
||||
|
||||
if (WITH_LTO)
|
||||
set(OPTIMIZATION_FLAGS "${OPTIMIZATION_FLAGS} -flto")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GENERAL_FLAGS} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 450)
|
||||
--start-mining N Start built-in miner using N threads (any value between 1 and 64)
|
||||
--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from 37889 to 37888
|
||||
--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum
|
||||
--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)
|
||||
--rpc-login Specify username[:password] required for Monero RPC server
|
||||
--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections
|
||||
--no-dns disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+1
-1
Submodule external/src/RandomX updated: 58c3943ff5...27a8cf0dfc
Vendored
+1
-1
Submodule external/src/curl updated: c12fb3ddaf...046209e561
Vendored
+1
-1
Submodule external/src/libzmq updated: bdd471fa17...8c725093ac
@@ -89,6 +89,16 @@
|
||||
#define P2POOL_DEBUGGING 1
|
||||
#endif
|
||||
|
||||
#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
extern "C" void __asan_poison_memory_region(void const volatile* addr, size_t size);
|
||||
extern "C" void __asan_unpoison_memory_region(void const volatile* addr, size_t size);
|
||||
#else
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size)
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
|
||||
#endif
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
constexpr size_t HASH_SIZE = 32;
|
||||
|
||||
@@ -176,7 +176,7 @@ INT_ENTRY(uint16_t)
|
||||
INT_ENTRY(uint32_t)
|
||||
INT_ENTRY(uint64_t)
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__OpenBSD__)
|
||||
INT_ENTRY(long)
|
||||
INT_ENTRY(unsigned long)
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ void p2pool_usage()
|
||||
"--in-peers N Maximum number of incoming connections for p2p server (any value between 10 and 450)\n"
|
||||
"--start-mining N Start built-in miner using N threads (any value between 1 and 64)\n"
|
||||
"--mini Connect to p2pool-mini sidechain. Note that it will also change default p2p port from %d to %d\n"
|
||||
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum\n"
|
||||
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)\n"
|
||||
"--rpc-login Specify username[:password] required for Monero RPC server\n"
|
||||
"--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections\n"
|
||||
"--no-dns disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)\n"
|
||||
|
||||
+63
-75
@@ -261,6 +261,8 @@ void P2PServer::on_connect_failed(bool is_v6, const raw_ip& ip, int port)
|
||||
|
||||
void P2PServer::update_peer_connections()
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const uint64_t last_updated = m_pool->side_chain().last_updated();
|
||||
|
||||
@@ -268,40 +270,37 @@ void P2PServer::update_peer_connections()
|
||||
m_fastestPeer = nullptr;
|
||||
|
||||
unordered_set<raw_ip> connected_clients;
|
||||
{
|
||||
MutexLock lock(m_clientsListLock);
|
||||
|
||||
connected_clients.reserve(m_numConnections);
|
||||
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
const int timeout = client->m_handshakeComplete ? 300 : 10;
|
||||
if ((cur_time >= client->m_lastAlive + timeout) && (client->m_socks5ProxyState == Client::Socks5ProxyState::Default)) {
|
||||
const uint64_t idle_time = static_cast<uint64_t>(cur_time - client->m_lastAlive);
|
||||
LOGWARN(5, "peer " << static_cast<char*>(client->m_addrString) << " has been idle for " << idle_time << " seconds, disconnecting");
|
||||
connected_clients.reserve(m_numConnections);
|
||||
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
const int timeout = client->m_handshakeComplete ? 300 : 10;
|
||||
if ((cur_time >= client->m_lastAlive + timeout) && (client->m_socks5ProxyState == Client::Socks5ProxyState::Default)) {
|
||||
const uint64_t idle_time = static_cast<uint64_t>(cur_time - client->m_lastAlive);
|
||||
LOGWARN(5, "peer " << static_cast<char*>(client->m_addrString) << " has been idle for " << idle_time << " seconds, disconnecting");
|
||||
client->close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (client->m_handshakeComplete && client->m_lastBroadcastTimestamp) {
|
||||
// - Side chain is at least 15 minutes newer (last_updated >= client->m_lastBroadcastTimestamp + 900)
|
||||
// - It's been at least 10 seconds since side chain updated (cur_time >= last_updated + 10)
|
||||
// - It's been at least 10 seconds since the last block request (peer is not syncing)
|
||||
// - Peer should have sent a broadcast by now
|
||||
if (last_updated && (cur_time >= std::max(last_updated, client->m_lastBlockrequestTimestamp) + 10) && (last_updated >= client->m_lastBroadcastTimestamp + 900)) {
|
||||
const uint64_t dt = last_updated - client->m_lastBroadcastTimestamp;
|
||||
LOGWARN(5, "peer " << static_cast<char*>(client->m_addrString) << " is not broadcasting blocks (last update " << dt << " seconds ago)");
|
||||
client->ban(DEFAULT_BAN_TIME);
|
||||
remove_peer_from_list(client);
|
||||
client->close();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->m_handshakeComplete && client->m_lastBroadcastTimestamp) {
|
||||
// - Side chain is at least 15 minutes newer (last_updated >= client->m_lastBroadcastTimestamp + 900)
|
||||
// - It's been at least 10 seconds since side chain updated (cur_time >= last_updated + 10)
|
||||
// - It's been at least 10 seconds since the last block request (peer is not syncing)
|
||||
// - Peer should have sent a broadcast by now
|
||||
if (last_updated && (cur_time >= std::max(last_updated, client->m_lastBlockrequestTimestamp) + 10) && (last_updated >= client->m_lastBroadcastTimestamp + 900)) {
|
||||
const uint64_t dt = last_updated - client->m_lastBroadcastTimestamp;
|
||||
LOGWARN(5, "peer " << static_cast<char*>(client->m_addrString) << " is not broadcasting blocks (last update " << dt << " seconds ago)");
|
||||
client->ban(DEFAULT_BAN_TIME);
|
||||
remove_peer_from_list(client);
|
||||
client->close();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
connected_clients.insert(client->m_addr);
|
||||
if (client->is_good()) {
|
||||
has_good_peers = true;
|
||||
if ((client->m_pingTime >= 0) && (!m_fastestPeer || (m_fastestPeer->m_pingTime > client->m_pingTime))) {
|
||||
m_fastestPeer = client;
|
||||
}
|
||||
connected_clients.insert(client->m_addr);
|
||||
if (client->is_good()) {
|
||||
has_good_peers = true;
|
||||
if ((client->m_pingTime >= 0) && (!m_fastestPeer || (m_fastestPeer->m_pingTime > client->m_pingTime))) {
|
||||
m_fastestPeer = client;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,7 +362,7 @@ void P2PServer::update_peer_connections()
|
||||
|
||||
void P2PServer::update_peer_list()
|
||||
{
|
||||
MutexLock lock(m_clientsListLock);
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
@@ -843,6 +842,8 @@ void P2PServer::broadcast(const PoolBlock& block, const PoolBlock* parent)
|
||||
|
||||
void P2PServer::on_broadcast()
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
std::vector<Broadcast*> broadcast_queue;
|
||||
broadcast_queue.reserve(2);
|
||||
|
||||
@@ -863,8 +864,6 @@ void P2PServer::on_broadcast()
|
||||
}
|
||||
});
|
||||
|
||||
MutexLock lock(m_clientsListLock);
|
||||
|
||||
for (P2PClient* client = static_cast<P2PClient*>(m_connectedClientsList->m_next); client != m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if (!client->is_good()) {
|
||||
continue;
|
||||
@@ -941,9 +940,7 @@ void P2PServer::on_broadcast()
|
||||
|
||||
uint64_t P2PServer::get_random64()
|
||||
{
|
||||
if (!server_event_loop_thread) {
|
||||
LOGERR(1, "get_random64() was called from another thread, this is not thread safe");
|
||||
}
|
||||
check_event_loop_thread(__func__);
|
||||
return m_rng();
|
||||
}
|
||||
|
||||
@@ -965,9 +962,9 @@ void P2PServer::show_peers_async()
|
||||
}
|
||||
}
|
||||
|
||||
void P2PServer::show_peers()
|
||||
void P2PServer::show_peers() const
|
||||
{
|
||||
MutexLock lock(m_clientsListLock);
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
size_t n = 0;
|
||||
@@ -1070,6 +1067,8 @@ void P2PServer::flush_cache()
|
||||
|
||||
void P2PServer::download_missing_blocks()
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
if (!m_lookForMissingBlocks) {
|
||||
return;
|
||||
}
|
||||
@@ -1083,8 +1082,6 @@ void P2PServer::download_missing_blocks()
|
||||
return;
|
||||
}
|
||||
|
||||
MutexLock lock(m_clientsListLock);
|
||||
|
||||
if (m_numConnections == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1271,7 +1268,6 @@ bool P2PServer::P2PClient::on_connect()
|
||||
}
|
||||
|
||||
// Don't allow multiple connections to/from the same IP (except localhost)
|
||||
// server->m_clientsListLock is already locked here
|
||||
if (!m_addr.is_localhost()) {
|
||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if ((client != this) && (client->m_addr == m_addr)) {
|
||||
@@ -1757,6 +1753,8 @@ bool P2PServer::P2PClient::check_handshake_solution(const hash& solution, const
|
||||
|
||||
bool P2PServer::P2PClient::on_handshake_challenge(const uint8_t* buf)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
|
||||
uint8_t challenge[CHALLENGE_SIZE];
|
||||
@@ -1772,23 +1770,14 @@ bool P2PServer::P2PClient::on_handshake_challenge(const uint8_t* buf)
|
||||
|
||||
m_peerId = peer_id;
|
||||
|
||||
bool same_peer = false;
|
||||
{
|
||||
MutexLock lock(server->m_clientsListLock);
|
||||
for (const P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if ((client != this) && (client->m_peerId == peer_id)) {
|
||||
LOGWARN(5, "tried to connect to the same peer twice: current connection " << static_cast<const char*>(client->m_addrString) << ", new connection " << static_cast<const char*>(m_addrString));
|
||||
same_peer = true;
|
||||
break;
|
||||
}
|
||||
for (const P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if ((client != this) && (client->m_peerId == peer_id)) {
|
||||
LOGWARN(5, "tried to connect to the same peer twice: current connection " << static_cast<const char*>(client->m_addrString) << ", new connection " << static_cast<const char*>(m_addrString));
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (same_peer) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
|
||||
send_handshake_solution(challenge);
|
||||
return true;
|
||||
}
|
||||
@@ -2033,6 +2022,8 @@ bool P2PServer::P2PClient::on_block_broadcast(const uint8_t* buf, uint32_t size,
|
||||
|
||||
bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
P2PServer* server = static_cast<P2PServer*>(m_owner);
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const bool first = (m_prevIncomingPeerListRequest == 0);
|
||||
@@ -2050,33 +2041,30 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
|
||||
|
||||
Peer peers[PEER_LIST_RESPONSE_MAX_PEERS];
|
||||
uint32_t num_selected_peers = 0;
|
||||
{
|
||||
MutexLock lock(server->m_clientsListLock);
|
||||
|
||||
// Send every 4th peer on average, selected at random
|
||||
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
||||
uint32_t n = 0;
|
||||
// Send every 4th peer on average, selected at random
|
||||
const uint32_t peers_to_send_target = std::min<uint32_t>(PEER_LIST_RESPONSE_MAX_PEERS, std::max<uint32_t>(1, server->m_numConnections / 4));
|
||||
uint32_t n = 0;
|
||||
|
||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if (!client->is_good() || (client->m_addr == m_addr)) {
|
||||
continue;
|
||||
}
|
||||
for (P2PClient* client = static_cast<P2PClient*>(server->m_connectedClientsList->m_next); client != server->m_connectedClientsList; client = static_cast<P2PClient*>(client->m_next)) {
|
||||
if (!client->is_good() || (client->m_addr == m_addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
||||
++n;
|
||||
const Peer p{ client->m_isV6, client->m_addr, client->m_listenPort, 0, 0 };
|
||||
++n;
|
||||
|
||||
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
||||
if (num_selected_peers < peers_to_send_target) {
|
||||
peers[num_selected_peers++] = p;
|
||||
continue;
|
||||
}
|
||||
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
|
||||
if (num_selected_peers < peers_to_send_target) {
|
||||
peers[num_selected_peers++] = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t k;
|
||||
umul128(server->get_random64(), n, &k);
|
||||
uint64_t k;
|
||||
umul128(server->get_random64(), n, &k);
|
||||
|
||||
if (k < peers_to_send_target) {
|
||||
peers[k] = p;
|
||||
}
|
||||
if (k < peers_to_send_target) {
|
||||
peers[k] = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -68,6 +68,7 @@ public:
|
||||
~P2PClient();
|
||||
|
||||
static Client* allocate() { return new P2PClient(); }
|
||||
virtual size_t size() const override { return sizeof(P2PClient); }
|
||||
|
||||
void reset() override;
|
||||
bool on_connect() override;
|
||||
@@ -252,7 +253,7 @@ private:
|
||||
uv_async_t m_showPeersAsync;
|
||||
|
||||
static void on_show_peers(uv_async_t* handle) { reinterpret_cast<P2PServer*>(handle->data)->show_peers(); }
|
||||
void show_peers();
|
||||
void show_peers() const;
|
||||
|
||||
void on_shutdown() override;
|
||||
};
|
||||
|
||||
+1
-2
@@ -668,9 +668,8 @@ void p2pool::update_block_template()
|
||||
{
|
||||
MinerData data = miner_data();
|
||||
|
||||
if (m_updateSeed) {
|
||||
if (m_updateSeed.exchange(false)) {
|
||||
m_hasher->set_seed_async(data.seed_hash);
|
||||
m_updateSeed = false;
|
||||
}
|
||||
m_blockTemplate->update(data, *m_mempool, &m_params->m_wallet);
|
||||
stratum_on_block();
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ private:
|
||||
SideChain* m_sideChain;
|
||||
RandomX_Hasher_Base* m_hasher;
|
||||
BlockTemplate* m_blockTemplate;
|
||||
bool m_updateSeed;
|
||||
std::atomic<bool> m_updateSeed;
|
||||
Mempool* m_mempool;
|
||||
|
||||
mutable uv_rwlock_t m_mainchainLock;
|
||||
|
||||
+100
-98
@@ -420,6 +420,7 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
|
||||
uint64_t rem;
|
||||
share->m_hashes = (target > 1) ? udiv128(1, 0, target, &rem) : 1;
|
||||
share->m_highEnoughDifficulty = sidechain_diff.check_pow(resultHash);
|
||||
share->m_score = 0;
|
||||
|
||||
// Don't count shares that were found during sync
|
||||
const SideChain& side_chain = m_pool->side_chain();
|
||||
@@ -484,11 +485,11 @@ void StratumServer::show_workers_async()
|
||||
|
||||
void StratumServer::show_workers()
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
const difficulty_type pool_diff = m_pool->side_chain().difficulty();
|
||||
|
||||
MutexLock lock(m_clientsListLock);
|
||||
|
||||
int addr_len = 0;
|
||||
for (const StratumClient* c = static_cast<StratumClient*>(m_connectedClientsList->m_next); c != m_connectedClientsList; c = static_cast<StratumClient*>(c->m_next)) {
|
||||
addr_len = std::max(addr_len, static_cast<int>(strlen(c->m_addrString)));
|
||||
@@ -529,9 +530,7 @@ void StratumServer::reset_share_counters()
|
||||
{
|
||||
WriteLock lock(m_hashrateDataLock);
|
||||
|
||||
m_cumulativeHashes = 0;
|
||||
m_cumulativeHashesAtLastShare = 0;
|
||||
m_cumulativeFoundSharesDiff = 0.0;
|
||||
m_cumulativeHashesAtLastShare = m_cumulativeHashes;
|
||||
m_totalFoundShares = 0;
|
||||
m_totalFailedShares = 0;
|
||||
}
|
||||
@@ -673,6 +672,8 @@ void StratumServer::update_auto_diff(StratumClient* client, const uint64_t times
|
||||
|
||||
void StratumServer::on_blobs_ready()
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
std::vector<BlobsData*> blobs_queue;
|
||||
blobs_queue.reserve(2);
|
||||
|
||||
@@ -701,101 +702,98 @@ void StratumServer::on_blobs_ready()
|
||||
uint32_t num_sent = 0;
|
||||
|
||||
const uint64_t cur_time = seconds_since_epoch();
|
||||
{
|
||||
MutexLock lock2(m_clientsListLock);
|
||||
|
||||
for (StratumClient* client = static_cast<StratumClient*>(m_connectedClientsList->m_prev); client != m_connectedClientsList; client = static_cast<StratumClient*>(client->m_prev)) {
|
||||
++numClientsProcessed;
|
||||
for (StratumClient* client = static_cast<StratumClient*>(m_connectedClientsList->m_prev); client != m_connectedClientsList; client = static_cast<StratumClient*>(client->m_prev)) {
|
||||
++numClientsProcessed;
|
||||
|
||||
if (!client->m_rpcId) {
|
||||
// Not logged in yet, on_login() will send the job to this client. Also close inactive connections.
|
||||
if (cur_time >= client->m_connectedTime + 10) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " didn't send login data");
|
||||
client->ban(DEFAULT_BAN_TIME);
|
||||
client->close();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num_sent >= data->m_numClientsExpected) {
|
||||
// We don't have any more extra_nonce values available
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* hashing_blob = data->m_blobs.data() + num_sent * data->m_blobSize;
|
||||
|
||||
uint64_t target = data->m_target;
|
||||
if (client->m_customDiff.lo) {
|
||||
target = std::max(target, client->m_customDiff.target());
|
||||
}
|
||||
else if (m_autoDiff) {
|
||||
// Limit autodiff to 4000000 for maximum compatibility
|
||||
target = std::max(target, TARGET_4_BYTES_LIMIT);
|
||||
|
||||
if (client->m_autoDiff.lo) {
|
||||
const uint32_t k = client->m_autoDiffIndex;
|
||||
const uint16_t elapsed_time = static_cast<uint16_t>(cur_time) - client->m_autoDiffData[(k - 1) % StratumClient::AUTO_DIFF_SIZE].m_timestamp;
|
||||
if (elapsed_time > AUTO_DIFF_TARGET_TIME * 5) {
|
||||
// More than 500% effort, reduce the auto diff by 1/8 every time until the share is found
|
||||
client->m_autoDiff.lo = std::max<uint64_t>(client->m_autoDiff.lo - client->m_autoDiff.lo / 8, MIN_DIFF);
|
||||
}
|
||||
target = std::max(target, client->m_autoDiff.target());
|
||||
}
|
||||
else {
|
||||
// Not enough shares from the client yet, cut diff in half every 16 seconds
|
||||
const uint64_t num_halvings = (cur_time - client->m_connectedTime) / 16;
|
||||
constexpr uint64_t max_target = (std::numeric_limits<uint64_t>::max() / MIN_DIFF) + 1;
|
||||
for (uint64_t i = 0; (i < num_halvings) && (target < max_target); ++i) {
|
||||
target *= 2;
|
||||
}
|
||||
target = std::min<uint64_t>(target, max_target);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t job_id;
|
||||
{
|
||||
job_id = ++client->m_perConnectionJobId;
|
||||
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
saved_job.job_id = job_id;
|
||||
saved_job.extra_nonce = extra_nonce_start + num_sent;
|
||||
saved_job.template_id = data->m_templateId;
|
||||
saved_job.target = target;
|
||||
}
|
||||
client->m_lastJobTarget = target;
|
||||
|
||||
const bool result = send(client,
|
||||
[data, target, hashing_blob, job_id](void* buf, size_t buf_size)
|
||||
{
|
||||
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
|
||||
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target_hex.m_data += sizeof(uint32_t);
|
||||
target_hex.m_size -= sizeof(uint32_t);
|
||||
}
|
||||
|
||||
log::Stream s(buf, buf_size);
|
||||
s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\"";
|
||||
s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\"";
|
||||
s << log::Hex(job_id) << "\",\"target\":\"";
|
||||
s << target_hex << "\",\"algo\":\"rx/0\",\"height\":";
|
||||
s << data->m_height << ",\"seed_hash\":\"";
|
||||
s << data->m_seedHash << "\"}}\n";
|
||||
return s.m_pos;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
++num_sent;
|
||||
}
|
||||
else {
|
||||
if (!client->m_rpcId) {
|
||||
// Not logged in yet, on_login() will send the job to this client. Also close inactive connections.
|
||||
if (cur_time >= client->m_connectedTime + 10) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " didn't send login data");
|
||||
client->ban(DEFAULT_BAN_TIME);
|
||||
client->close();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t num_connections = m_numConnections;
|
||||
if (numClientsProcessed != num_connections) {
|
||||
LOGWARN(1, "client list is broken, expected " << num_connections << ", got " << numClientsProcessed << " clients");
|
||||
if (num_sent >= data->m_numClientsExpected) {
|
||||
// We don't have any more extra_nonce values available
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* hashing_blob = data->m_blobs.data() + num_sent * data->m_blobSize;
|
||||
|
||||
uint64_t target = data->m_target;
|
||||
if (client->m_customDiff.lo) {
|
||||
target = std::max(target, client->m_customDiff.target());
|
||||
}
|
||||
else if (m_autoDiff) {
|
||||
// Limit autodiff to 4000000 for maximum compatibility
|
||||
target = std::max(target, TARGET_4_BYTES_LIMIT);
|
||||
|
||||
if (client->m_autoDiff.lo) {
|
||||
const uint32_t k = client->m_autoDiffIndex;
|
||||
const uint16_t elapsed_time = static_cast<uint16_t>(cur_time) - client->m_autoDiffData[(k - 1) % StratumClient::AUTO_DIFF_SIZE].m_timestamp;
|
||||
if (elapsed_time > AUTO_DIFF_TARGET_TIME * 5) {
|
||||
// More than 500% effort, reduce the auto diff by 1/8 every time until the share is found
|
||||
client->m_autoDiff.lo = std::max<uint64_t>(client->m_autoDiff.lo - client->m_autoDiff.lo / 8, MIN_DIFF);
|
||||
}
|
||||
target = std::max(target, client->m_autoDiff.target());
|
||||
}
|
||||
else {
|
||||
// Not enough shares from the client yet, cut diff in half every 16 seconds
|
||||
const uint64_t num_halvings = (cur_time - client->m_connectedTime) / 16;
|
||||
constexpr uint64_t max_target = (std::numeric_limits<uint64_t>::max() / MIN_DIFF) + 1;
|
||||
for (uint64_t i = 0; (i < num_halvings) && (target < max_target); ++i) {
|
||||
target *= 2;
|
||||
}
|
||||
target = std::min<uint64_t>(target, max_target);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t job_id;
|
||||
{
|
||||
job_id = ++client->m_perConnectionJobId;
|
||||
|
||||
StratumClient::SavedJob& saved_job = client->m_jobs[job_id % StratumClient::JOBS_SIZE];
|
||||
saved_job.job_id = job_id;
|
||||
saved_job.extra_nonce = extra_nonce_start + num_sent;
|
||||
saved_job.template_id = data->m_templateId;
|
||||
saved_job.target = target;
|
||||
}
|
||||
client->m_lastJobTarget = target;
|
||||
|
||||
const bool result = send(client,
|
||||
[data, target, hashing_blob, job_id](void* buf, size_t buf_size)
|
||||
{
|
||||
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
|
||||
|
||||
if (target >= TARGET_4_BYTES_LIMIT) {
|
||||
target_hex.m_data += sizeof(uint32_t);
|
||||
target_hex.m_size -= sizeof(uint32_t);
|
||||
}
|
||||
|
||||
log::Stream s(buf, buf_size);
|
||||
s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\"";
|
||||
s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\"";
|
||||
s << log::Hex(job_id) << "\",\"target\":\"";
|
||||
s << target_hex << "\",\"algo\":\"rx/0\",\"height\":";
|
||||
s << data->m_height << ",\"seed_hash\":\"";
|
||||
s << data->m_seedHash << "\"}}\n";
|
||||
return s.m_pos;
|
||||
});
|
||||
|
||||
if (result) {
|
||||
++num_sent;
|
||||
}
|
||||
else {
|
||||
client->close();
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t num_connections = m_numConnections;
|
||||
if (numClientsProcessed != num_connections) {
|
||||
LOGWARN(1, "client list is broken, expected " << num_connections << ", got " << numClientsProcessed << " clients");
|
||||
}
|
||||
|
||||
LOGINFO(3, "sent new job to " << num_sent << '/' << numClientsProcessed << " clients");
|
||||
@@ -887,11 +885,11 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
if (pow_hash != share->m_resultHash) {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " submitted a share with invalid PoW");
|
||||
share->m_result = SubmittedShare::Result::INVALID_POW;
|
||||
client->m_score += BAD_SHARE_POINTS;
|
||||
share->m_score = BAD_SHARE_POINTS;
|
||||
return;
|
||||
}
|
||||
|
||||
client->m_score += GOOD_SHARE_POINTS;
|
||||
share->m_score = GOOD_SHARE_POINTS;
|
||||
|
||||
const double diff = sidechain_difficulty.to_double();
|
||||
{
|
||||
@@ -927,7 +925,7 @@ void StratumServer::on_share_found(uv_work_t* req)
|
||||
else {
|
||||
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a low diff share");
|
||||
share->m_result = SubmittedShare::Result::LOW_DIFF;
|
||||
client->m_score += BAD_SHARE_POINTS;
|
||||
share->m_score = BAD_SHARE_POINTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,6 +933,7 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
|
||||
{
|
||||
SubmittedShare* share = reinterpret_cast<SubmittedShare*>(req->data);
|
||||
StratumClient* client = share->m_client;
|
||||
client->m_score += share->m_score;
|
||||
|
||||
if (share->m_highEnoughDifficulty) {
|
||||
const char* s = client->m_customUser;
|
||||
@@ -1229,11 +1228,14 @@ void StratumServer::api_update_local_stats(uint64_t timestamp)
|
||||
}
|
||||
|
||||
// Rate limit to no more than once in 60 seconds.
|
||||
if (timestamp < m_apiLastUpdateTime + 60) {
|
||||
uint64_t t = m_apiLastUpdateTime.load();
|
||||
if (timestamp < t + 60) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_apiLastUpdateTime = timestamp;
|
||||
if (!m_apiLastUpdateTime.compare_exchange_strong(t, timestamp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t hashes_15m, hashes_1h, hashes_24h, total_hashes;
|
||||
int64_t dt_15m, dt_1h, dt_24h;
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
FORCEINLINE ~StratumClient() {}
|
||||
|
||||
static Client* allocate() { return new StratumClient(); }
|
||||
virtual size_t size() const override { return sizeof(StratumClient); }
|
||||
|
||||
void reset() override;
|
||||
bool on_connect() override;
|
||||
@@ -153,6 +154,7 @@ private:
|
||||
uint64_t m_timestamp;
|
||||
uint64_t m_hashes;
|
||||
bool m_highEnoughDifficulty;
|
||||
int32_t m_score;
|
||||
|
||||
enum class Result {
|
||||
STALE,
|
||||
@@ -186,7 +188,7 @@ private:
|
||||
uint32_t m_totalFoundShares;
|
||||
uint32_t m_totalFailedShares;
|
||||
|
||||
uint64_t m_apiLastUpdateTime;
|
||||
std::atomic<uint64_t> m_apiLastUpdateTime;
|
||||
|
||||
void update_hashrate_data(uint64_t hashes, uint64_t timestamp);
|
||||
void api_update_local_stats(uint64_t timestamp);
|
||||
|
||||
+15
-1
@@ -55,6 +55,8 @@ public:
|
||||
Client();
|
||||
virtual ~Client() {}
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
virtual void reset();
|
||||
virtual bool on_connect() = 0;
|
||||
virtual bool on_read(char* data, uint32_t size) = 0;
|
||||
@@ -110,6 +112,9 @@ public:
|
||||
|
||||
std::vector<WriteBuf*> m_writeBuffers;
|
||||
|
||||
WriteBuf* get_write_buffer();
|
||||
void return_write_buffer(WriteBuf* buf);
|
||||
|
||||
struct SendCallbackBase
|
||||
{
|
||||
virtual ~SendCallbackBase() {}
|
||||
@@ -165,8 +170,17 @@ protected:
|
||||
|
||||
uv_loop_t m_loop;
|
||||
|
||||
uv_mutex_t m_clientsListLock;
|
||||
#ifdef P2POOL_DEBUGGING
|
||||
static void check_event_loop_thread(const char *func);
|
||||
#else
|
||||
static FORCEINLINE void check_event_loop_thread(const char*) {}
|
||||
#endif
|
||||
|
||||
std::vector<Client*> m_preallocatedClients;
|
||||
|
||||
Client* get_client();
|
||||
void return_client(Client* c);
|
||||
|
||||
Client* m_connectedClientsList;
|
||||
std::atomic<uint32_t> m_numConnections;
|
||||
std::atomic<uint32_t> m_numIncomingConnections;
|
||||
|
||||
+105
-73
@@ -61,7 +61,6 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
|
||||
}
|
||||
m_shutdownAsync.data = this;
|
||||
|
||||
uv_mutex_init_checked(&m_clientsListLock);
|
||||
uv_mutex_init_checked(&m_bansLock);
|
||||
|
||||
m_connectedClientsList = m_allocateNewClient();
|
||||
@@ -226,23 +225,13 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const
|
||||
return false;
|
||||
}
|
||||
|
||||
Client* client;
|
||||
|
||||
if (!m_preallocatedClients.empty()) {
|
||||
client = m_preallocatedClients.back();
|
||||
m_preallocatedClients.pop_back();
|
||||
client->reset();
|
||||
}
|
||||
else {
|
||||
client = m_allocateNewClient();
|
||||
}
|
||||
|
||||
Client* client = get_client();
|
||||
client->m_owner = this;
|
||||
client->m_port = port;
|
||||
client->m_isV6 = is_v6;
|
||||
|
||||
if (!str_to_ip(is_v6, ip, client->m_addr)) {
|
||||
m_preallocatedClients.push_back(client);
|
||||
return_client(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -264,17 +253,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(bool is_v6, const
|
||||
return false;
|
||||
}
|
||||
|
||||
Client* client;
|
||||
|
||||
if (!m_preallocatedClients.empty()) {
|
||||
client = m_preallocatedClients.back();
|
||||
m_preallocatedClients.pop_back();
|
||||
client->reset();
|
||||
}
|
||||
else {
|
||||
client = m_allocateNewClient();
|
||||
}
|
||||
|
||||
Client* client = get_client();
|
||||
client->m_owner = this;
|
||||
client->m_addr = ip;
|
||||
client->m_port = port;
|
||||
@@ -312,20 +291,20 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
{
|
||||
if (is_banned(client->m_addr)) {
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " is banned, not connecting to it");
|
||||
m_preallocatedClients.push_back(client);
|
||||
return_client(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_pendingConnections.insert(client->m_addr).second) {
|
||||
LOGINFO(6, "there is already a pending connection to this IP, not connecting to " << log::Gray() << static_cast<char*>(client->m_addrString));
|
||||
m_preallocatedClients.push_back(client);
|
||||
return_client(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
int err = uv_tcp_init(&m_loop, &client->m_socket);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create tcp client handle, error " << uv_err_name(err));
|
||||
m_preallocatedClients.push_back(client);
|
||||
return_client(client);
|
||||
return false;
|
||||
}
|
||||
client->m_socket.data = client;
|
||||
@@ -388,12 +367,20 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::connect_to_peer(Client* client)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef P2POOL_DEBUGGING
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::check_event_loop_thread(const char* func)
|
||||
{
|
||||
if (!server_event_loop_thread) {
|
||||
LOGERR(1, func << " called from another thread, this is not thread safe");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::close_sockets(bool listen_sockets)
|
||||
{
|
||||
if (!server_event_loop_thread) {
|
||||
LOGERR(1, "closing sockets from another thread, this is not thread safe");
|
||||
}
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
if (listen_sockets) {
|
||||
for (uv_tcp_t* s : m_listenSockets6) {
|
||||
@@ -411,15 +398,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::close_sockets(bool listen_sockets
|
||||
}
|
||||
|
||||
size_t numClosed = 0;
|
||||
{
|
||||
MutexLock lock(m_clientsListLock);
|
||||
|
||||
for (Client* c = m_connectedClientsList->m_next; c != m_connectedClientsList; c = c->m_next) {
|
||||
uv_handle_t* h = reinterpret_cast<uv_handle_t*>(&c->m_socket);
|
||||
if (!uv_is_closing(h)) {
|
||||
uv_close(h, on_connection_close);
|
||||
++numClosed;
|
||||
}
|
||||
for (Client* c = m_connectedClientsList->m_next; c != m_connectedClientsList; c = c->m_next) {
|
||||
uv_handle_t* h = reinterpret_cast<uv_handle_t*>(&c->m_socket);
|
||||
if (!uv_is_closing(h)) {
|
||||
uv_close(h, on_connection_close);
|
||||
++numClosed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +422,6 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::shutdown_tcp()
|
||||
uv_async_send(&m_shutdownAsync);
|
||||
uv_thread_join(&m_loopThread);
|
||||
|
||||
uv_mutex_destroy(&m_clientsListLock);
|
||||
uv_mutex_destroy(&m_bansLock);
|
||||
|
||||
LOGINFO(1, "stopped");
|
||||
@@ -484,24 +467,14 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::print_bans()
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, SendCallbackBase&& callback)
|
||||
{
|
||||
if (!server_event_loop_thread) {
|
||||
LOGERR(1, "sending data from another thread, this is not thread safe");
|
||||
}
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
if (client->m_isClosing) {
|
||||
LOGWARN(5, "client " << static_cast<const char*>(client->m_addrString) << " is being disconnected, can't send any more data");
|
||||
return true;
|
||||
}
|
||||
|
||||
WriteBuf* buf;
|
||||
|
||||
if (!m_writeBuffers.empty()) {
|
||||
buf = m_writeBuffers.back();
|
||||
m_writeBuffers.pop_back();
|
||||
}
|
||||
else {
|
||||
buf = new WriteBuf();
|
||||
}
|
||||
WriteBuf* buf = get_write_buffer();
|
||||
|
||||
// callback_buf is used in only 1 thread, so it's safe
|
||||
static uint8_t callback_buf[WRITE_BUF_SIZE];
|
||||
@@ -514,7 +487,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
|
||||
|
||||
if (bytes_written == 0) {
|
||||
LOGWARN(1, "send callback wrote 0 bytes, nothing to do");
|
||||
m_writeBuffers.push_back(buf);
|
||||
return_write_buffer(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -539,7 +512,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
|
||||
const int err = uv_write(&buf->m_write, reinterpret_cast<uv_stream_t*>(&client->m_socket), bufs, 1, Client::on_write);
|
||||
if (err) {
|
||||
LOGWARN(1, "failed to start writing data to client connection " << static_cast<const char*>(client->m_addrString) << ", error " << uv_err_name(err));
|
||||
m_writeBuffers.push_back(buf);
|
||||
return_write_buffer(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -556,8 +529,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
server->m_writeBuffers.resize(DEFAULT_BACKLOG);
|
||||
server->m_preallocatedClients.reserve(DEFAULT_BACKLOG);
|
||||
for (size_t i = 0; i < DEFAULT_BACKLOG; ++i) {
|
||||
server->m_writeBuffers[i] = new WriteBuf();
|
||||
server->m_preallocatedClients.emplace_back(server->m_allocateNewClient());
|
||||
WriteBuf* wb = new WriteBuf();
|
||||
Client* c = server->m_allocateNewClient();
|
||||
ASAN_POISON_MEMORY_REGION(wb, sizeof(WriteBuf));
|
||||
ASAN_POISON_MEMORY_REGION(c, c->size());
|
||||
server->m_writeBuffers[i] = wb;
|
||||
server->m_preallocatedClients.emplace_back(c);
|
||||
}
|
||||
|
||||
int err = uv_run(&server->m_loop, UV_RUN_DEFAULT);
|
||||
@@ -571,12 +548,18 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
|
||||
}
|
||||
|
||||
for (WriteBuf* buf : server->m_writeBuffers) {
|
||||
free_hook(buf->m_data);
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
if (buf->m_data) {
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf->m_data, buf->m_dataCapacity);
|
||||
free_hook(buf->m_data);
|
||||
}
|
||||
delete buf;
|
||||
}
|
||||
server->m_writeBuffers.clear();
|
||||
|
||||
for (Client* c : server->m_preallocatedClients) {
|
||||
ASAN_UNPOISON_MEMORY_REGION(c, sizeof(Client));
|
||||
ASAN_UNPOISON_MEMORY_REGION(c, c->size());
|
||||
delete c;
|
||||
}
|
||||
server->m_preallocatedClients.clear();
|
||||
@@ -604,14 +587,14 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_connection(uv_stream_t* se
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_close(uv_handle_t* handle)
|
||||
{
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
Client* client = static_cast<Client*>(handle->data);
|
||||
TCPServer* owner = client->m_owner;
|
||||
|
||||
LOGINFO(5, "peer " << log::Gray() << static_cast<char*>(client->m_addrString) << log::NoColor() << " disconnected");
|
||||
|
||||
if (owner) {
|
||||
MutexLock lock(owner->m_clientsListLock);
|
||||
|
||||
Client* prev_in_list = client->m_prev;
|
||||
Client* next_in_list = client->m_next;
|
||||
|
||||
@@ -622,7 +605,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_close(uv_handle_t*
|
||||
prev_in_list->m_next = next_in_list;
|
||||
next_in_list->m_prev = prev_in_list;
|
||||
|
||||
owner->m_preallocatedClients.push_back(client);
|
||||
owner->return_client(client);
|
||||
|
||||
--owner->m_numConnections;
|
||||
if (is_incoming) {
|
||||
@@ -638,7 +621,7 @@ template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_connection_error(uv_handle_t* handle)
|
||||
{
|
||||
Client* client = reinterpret_cast<Client*>(handle->data);
|
||||
client->m_owner->m_preallocatedClients.push_back(client);
|
||||
client->m_owner->return_client(client);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
@@ -675,21 +658,12 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
return;
|
||||
}
|
||||
|
||||
Client* client;
|
||||
|
||||
if (!m_preallocatedClients.empty()) {
|
||||
client = m_preallocatedClients.back();
|
||||
m_preallocatedClients.pop_back();
|
||||
client->reset();
|
||||
}
|
||||
else {
|
||||
client = m_allocateNewClient();
|
||||
}
|
||||
Client* client = get_client();
|
||||
|
||||
int err = uv_tcp_init(&m_loop, &client->m_socket);
|
||||
if (err) {
|
||||
LOGERR(1, "failed to create tcp client handle, error " << uv_err_name(err));
|
||||
m_preallocatedClients.push_back(client);
|
||||
return_client(client);
|
||||
return;
|
||||
}
|
||||
client->m_socket.data = client;
|
||||
@@ -715,7 +689,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_new_client(uv_stream_t* server, Client* client)
|
||||
{
|
||||
MutexLock lock(m_clientsListLock);
|
||||
check_event_loop_thread(__func__);
|
||||
|
||||
client->m_prev = m_connectedClientsList;
|
||||
client->m_next = m_connectedClientsList->m_next;
|
||||
@@ -868,6 +842,64 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::on_shutdown(uv_async_t* async)
|
||||
});
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::WriteBuf* TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::get_write_buffer()
|
||||
{
|
||||
WriteBuf* buf;
|
||||
|
||||
if (!m_writeBuffers.empty()) {
|
||||
buf = m_writeBuffers.back();
|
||||
m_writeBuffers.pop_back();
|
||||
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
if (buf->m_data) {
|
||||
ASAN_UNPOISON_MEMORY_REGION(buf->m_data, buf->m_dataCapacity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf = new WriteBuf();
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::return_write_buffer(WriteBuf* buf)
|
||||
{
|
||||
if (buf->m_data) {
|
||||
ASAN_POISON_MEMORY_REGION(buf->m_data, buf->m_dataCapacity);
|
||||
}
|
||||
ASAN_POISON_MEMORY_REGION(buf, sizeof(WriteBuf));
|
||||
|
||||
m_writeBuffers.push_back(buf);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
typename TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client* TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::get_client()
|
||||
{
|
||||
Client* c;
|
||||
|
||||
if (!m_preallocatedClients.empty()) {
|
||||
c = m_preallocatedClients.back();
|
||||
m_preallocatedClients.pop_back();
|
||||
ASAN_UNPOISON_MEMORY_REGION(c, sizeof(Client));
|
||||
ASAN_UNPOISON_MEMORY_REGION(c, c->size());
|
||||
c->reset();
|
||||
}
|
||||
else {
|
||||
c = m_allocateNewClient();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::return_client(Client* c)
|
||||
{
|
||||
ASAN_POISON_MEMORY_REGION(c, c->size());
|
||||
m_preallocatedClients.push_back(c);
|
||||
}
|
||||
|
||||
template<size_t READ_BUF_SIZE, size_t WRITE_BUF_SIZE>
|
||||
TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::Client()
|
||||
: m_owner(nullptr)
|
||||
@@ -1101,7 +1133,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::Client::on_write(uv_write_t* req,
|
||||
TCPServer* server = client->m_owner;
|
||||
|
||||
if (server) {
|
||||
server->m_writeBuffers.push_back(buf);
|
||||
server->return_write_buffer(buf);
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
|
||||
@@ -331,6 +331,7 @@ struct BackgroundJobTracker::Impl
|
||||
do {
|
||||
{
|
||||
MutexLock lock(m_lock);
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (m_jobs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
namespace p2pool {
|
||||
|
||||
#define P2POOL_VERSION_MAJOR 3
|
||||
#define P2POOL_VERSION_MINOR 0
|
||||
#define P2POOL_VERSION_MINOR 1
|
||||
|
||||
extern const char* VERSION;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ TEST(block_template, update)
|
||||
tpl.update(data, mempool, &wallet);
|
||||
|
||||
const PoolBlock* b = tpl.pool_block_template();
|
||||
ASSERT_EQ(b->m_sidechainId, H("d52dba078bc2b581edf3ff27fb46e218bd2568b1f2126bd65cc1a0f9f6bbd00f"));
|
||||
ASSERT_EQ(b->m_sidechainId, H("5b6d5ac9e8cc8b973cedbf6114584b79f03f9d7d9d413a8f7e6fc398aac1a26c"));
|
||||
|
||||
std::vector<uint8_t> blobs;
|
||||
uint64_t height;
|
||||
@@ -79,7 +79,7 @@ TEST(block_template, update)
|
||||
|
||||
hash blobs_hash;
|
||||
keccak(blobs.data(), static_cast<int>(blobs.size()), blobs_hash.h);
|
||||
ASSERT_EQ(blobs_hash, H("ea63225d0f4b21bb15bfdc92e25a1dc4de2e052062db6c33679da854be158e9a"));
|
||||
ASSERT_EQ(blobs_hash, H("a500d8d337db35f8c3e8e70dea78122ea3cfb87874245bbc4e5f48892e8d1cb1"));
|
||||
|
||||
// Test 2: mempool with high fee and low fee transactions, it must choose high fee transactions
|
||||
for (uint64_t i = 0; i < 512; ++i) {
|
||||
|
||||
Reference in New Issue
Block a user