mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 06:52:36 +01:00
net: Use mockable time for ping/pong, add tests
This commit is contained in:
parent
faab4aaf2f
commit
fa3365430c
9 changed files with 166 additions and 34 deletions
21
src/net.cpp
21
src/net.cpp
|
@ -563,15 +563,15 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
|
||||||
// since pingtime does not update until the ping is complete, which might take a while.
|
// since pingtime does not update until the ping is complete, which might take a while.
|
||||||
// So, if a ping is taking an unusually long time in flight,
|
// So, if a ping is taking an unusually long time in flight,
|
||||||
// the caller can immediately detect that this is happening.
|
// the caller can immediately detect that this is happening.
|
||||||
int64_t nPingUsecWait = 0;
|
std::chrono::microseconds ping_wait{0};
|
||||||
if ((0 != nPingNonceSent) && (0 != nPingUsecStart)) {
|
if ((0 != nPingNonceSent) && (0 != m_ping_start.load().count())) {
|
||||||
nPingUsecWait = GetTimeMicros() - nPingUsecStart;
|
ping_wait = GetTime<std::chrono::microseconds>() - m_ping_start.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
|
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
|
||||||
stats.m_ping_usec = nPingUsecTime;
|
stats.m_ping_usec = nPingUsecTime;
|
||||||
stats.m_min_ping_usec = nMinPingUsecTime;
|
stats.m_min_ping_usec = nMinPingUsecTime;
|
||||||
stats.m_ping_wait_usec = nPingUsecWait;
|
stats.m_ping_wait_usec = count_microseconds(ping_wait);
|
||||||
|
|
||||||
// Leave string empty if addrLocal invalid (not filled in yet)
|
// Leave string empty if addrLocal invalid (not filled in yet)
|
||||||
CService addrLocalUnlocked = GetAddrLocal();
|
CService addrLocalUnlocked = GetAddrLocal();
|
||||||
|
@ -582,9 +582,9 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
|
||||||
bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete)
|
bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete)
|
||||||
{
|
{
|
||||||
complete = false;
|
complete = false;
|
||||||
int64_t nTimeMicros = GetTimeMicros();
|
const auto time = GetTime<std::chrono::microseconds>();
|
||||||
LOCK(cs_vRecv);
|
LOCK(cs_vRecv);
|
||||||
nLastRecv = nTimeMicros / 1000000;
|
nLastRecv = std::chrono::duration_cast<std::chrono::seconds>(time).count();
|
||||||
nRecvBytes += nBytes;
|
nRecvBytes += nBytes;
|
||||||
while (nBytes > 0) {
|
while (nBytes > 0) {
|
||||||
// absorb network data
|
// absorb network data
|
||||||
|
@ -596,7 +596,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
|
||||||
|
|
||||||
if (m_deserializer->Complete()) {
|
if (m_deserializer->Complete()) {
|
||||||
// decompose a transport agnostic CNetMessage from the deserializer
|
// decompose a transport agnostic CNetMessage from the deserializer
|
||||||
CNetMessage msg = m_deserializer->GetMessage(Params().MessageStart(), nTimeMicros);
|
CNetMessage msg = m_deserializer->GetMessage(Params().MessageStart(), time);
|
||||||
|
|
||||||
//store received bytes per message command
|
//store received bytes per message command
|
||||||
//to prevent a memory DOS, only allow valid commands
|
//to prevent a memory DOS, only allow valid commands
|
||||||
|
@ -699,7 +699,8 @@ const uint256& V1TransportDeserializer::GetMessageHash() const
|
||||||
return data_hash;
|
return data_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageStartChars& message_start, int64_t time) {
|
CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageStartChars& message_start, const std::chrono::microseconds time)
|
||||||
|
{
|
||||||
// decompose a single CNetMessage from the TransportDeserializer
|
// decompose a single CNetMessage from the TransportDeserializer
|
||||||
CNetMessage msg(std::move(vRecv));
|
CNetMessage msg(std::move(vRecv));
|
||||||
|
|
||||||
|
@ -1154,9 +1155,9 @@ void CConnman::InactivityCheck(CNode *pnode)
|
||||||
LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
|
LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
|
||||||
pnode->fDisconnect = true;
|
pnode->fDisconnect = true;
|
||||||
}
|
}
|
||||||
else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
|
else if (pnode->nPingNonceSent && pnode->m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>())
|
||||||
{
|
{
|
||||||
LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
|
LogPrintf("ping timeout: %fs\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - pnode->m_ping_start.load()));
|
||||||
pnode->fDisconnect = true;
|
pnode->fDisconnect = true;
|
||||||
}
|
}
|
||||||
else if (!pnode->fSuccessfullyConnected)
|
else if (!pnode->fSuccessfullyConnected)
|
||||||
|
|
16
src/net.h
16
src/net.h
|
@ -612,13 +612,13 @@ public:
|
||||||
*/
|
*/
|
||||||
class CNetMessage {
|
class CNetMessage {
|
||||||
public:
|
public:
|
||||||
CDataStream m_recv; // received message data
|
CDataStream m_recv; //!< received message data
|
||||||
int64_t m_time = 0; // time (in microseconds) of message receipt.
|
std::chrono::microseconds m_time{0}; //!< time of message receipt
|
||||||
bool m_valid_netmagic = false;
|
bool m_valid_netmagic = false;
|
||||||
bool m_valid_header = false;
|
bool m_valid_header = false;
|
||||||
bool m_valid_checksum = false;
|
bool m_valid_checksum = false;
|
||||||
uint32_t m_message_size = 0; // size of the payload
|
uint32_t m_message_size{0}; //!< size of the payload
|
||||||
uint32_t m_raw_message_size = 0; // used wire size of the message (including header/checksum)
|
uint32_t m_raw_message_size{0}; //!< used wire size of the message (including header/checksum)
|
||||||
std::string m_command;
|
std::string m_command;
|
||||||
|
|
||||||
CNetMessage(CDataStream&& recv_in) : m_recv(std::move(recv_in)) {}
|
CNetMessage(CDataStream&& recv_in) : m_recv(std::move(recv_in)) {}
|
||||||
|
@ -642,7 +642,7 @@ public:
|
||||||
// read and deserialize data
|
// read and deserialize data
|
||||||
virtual int Read(const char *data, unsigned int bytes) = 0;
|
virtual int Read(const char *data, unsigned int bytes) = 0;
|
||||||
// decomposes a message from the context
|
// decomposes a message from the context
|
||||||
virtual CNetMessage GetMessage(const CMessageHeader::MessageStartChars& message_start, int64_t time) = 0;
|
virtual CNetMessage GetMessage(const CMessageHeader::MessageStartChars& message_start, std::chrono::microseconds time) = 0;
|
||||||
virtual ~TransportDeserializer() {}
|
virtual ~TransportDeserializer() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ public:
|
||||||
if (ret < 0) Reset();
|
if (ret < 0) Reset();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
CNetMessage GetMessage(const CMessageHeader::MessageStartChars& message_start, int64_t time) override;
|
CNetMessage GetMessage(const CMessageHeader::MessageStartChars& message_start, std::chrono::microseconds time) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The TransportSerializer prepares messages for the network transport
|
/** The TransportSerializer prepares messages for the network transport
|
||||||
|
@ -845,8 +845,8 @@ public:
|
||||||
// Ping time measurement:
|
// Ping time measurement:
|
||||||
// The pong reply we're expecting, or 0 if no pong expected.
|
// The pong reply we're expecting, or 0 if no pong expected.
|
||||||
std::atomic<uint64_t> nPingNonceSent{0};
|
std::atomic<uint64_t> nPingNonceSent{0};
|
||||||
// Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
|
/** When the last ping was sent, or 0 if no ping was ever sent */
|
||||||
std::atomic<int64_t> nPingUsecStart{0};
|
std::atomic<std::chrono::microseconds> m_ping_start{std::chrono::microseconds{0}};
|
||||||
// Last measured round-trip time.
|
// Last measured round-trip time.
|
||||||
std::atomic<int64_t> nPingUsecTime{0};
|
std::atomic<int64_t> nPingUsecTime{0};
|
||||||
// Best measured round-trip time.
|
// Best measured round-trip time.
|
||||||
|
|
|
@ -66,8 +66,8 @@ static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60;
|
||||||
/// Age after which a block is considered historical for purposes of rate
|
/// Age after which a block is considered historical for purposes of rate
|
||||||
/// limiting block relay. Set to one week, denominated in seconds.
|
/// limiting block relay. Set to one week, denominated in seconds.
|
||||||
static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60;
|
static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60;
|
||||||
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
|
/** Time between pings automatically sent out for latency probing and keepalive */
|
||||||
static const int PING_INTERVAL = 2 * 60;
|
static constexpr std::chrono::minutes PING_INTERVAL{2};
|
||||||
/** The maximum number of entries in a locator */
|
/** The maximum number of entries in a locator */
|
||||||
static const unsigned int MAX_LOCATOR_SZ = 101;
|
static const unsigned int MAX_LOCATOR_SZ = 101;
|
||||||
/** The maximum number of entries in an 'inv' protocol message */
|
/** The maximum number of entries in an 'inv' protocol message */
|
||||||
|
@ -2208,7 +2208,7 @@ void ProcessMessage(
|
||||||
CNode& pfrom,
|
CNode& pfrom,
|
||||||
const std::string& msg_type,
|
const std::string& msg_type,
|
||||||
CDataStream& vRecv,
|
CDataStream& vRecv,
|
||||||
int64_t nTimeReceived,
|
const std::chrono::microseconds time_received,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
ChainstateManager& chainman,
|
ChainstateManager& chainman,
|
||||||
CTxMemPool& mempool,
|
CTxMemPool& mempool,
|
||||||
|
@ -3111,7 +3111,7 @@ void ProcessMessage(
|
||||||
} // cs_main
|
} // cs_main
|
||||||
|
|
||||||
if (fProcessBLOCKTXN)
|
if (fProcessBLOCKTXN)
|
||||||
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, chainman, mempool, connman, banman, interruptMsgProc);
|
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, chainparams, chainman, mempool, connman, banman, interruptMsgProc);
|
||||||
|
|
||||||
if (fRevertToHeaderProcessing) {
|
if (fRevertToHeaderProcessing) {
|
||||||
// Headers received from HB compact block peers are permitted to be
|
// Headers received from HB compact block peers are permitted to be
|
||||||
|
@ -3386,7 +3386,7 @@ void ProcessMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_type == NetMsgType::PONG) {
|
if (msg_type == NetMsgType::PONG) {
|
||||||
int64_t pingUsecEnd = nTimeReceived;
|
const auto ping_end = time_received;
|
||||||
uint64_t nonce = 0;
|
uint64_t nonce = 0;
|
||||||
size_t nAvail = vRecv.in_avail();
|
size_t nAvail = vRecv.in_avail();
|
||||||
bool bPingFinished = false;
|
bool bPingFinished = false;
|
||||||
|
@ -3400,11 +3400,11 @@ void ProcessMessage(
|
||||||
if (nonce == pfrom.nPingNonceSent) {
|
if (nonce == pfrom.nPingNonceSent) {
|
||||||
// Matching pong received, this ping is no longer outstanding
|
// Matching pong received, this ping is no longer outstanding
|
||||||
bPingFinished = true;
|
bPingFinished = true;
|
||||||
int64_t pingUsecTime = pingUsecEnd - pfrom.nPingUsecStart;
|
const auto ping_time = ping_end - pfrom.m_ping_start.load();
|
||||||
if (pingUsecTime > 0) {
|
if (ping_time.count() > 0) {
|
||||||
// Successful ping time measurement, replace previous
|
// Successful ping time measurement, replace previous
|
||||||
pfrom.nPingUsecTime = pingUsecTime;
|
pfrom.nPingUsecTime = count_microseconds(ping_time);
|
||||||
pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), pingUsecTime);
|
pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), count_microseconds(ping_time));
|
||||||
} else {
|
} else {
|
||||||
// This should never happen
|
// This should never happen
|
||||||
sProblem = "Timing mishap";
|
sProblem = "Timing mishap";
|
||||||
|
@ -3860,7 +3860,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
||||||
// RPC ping request by user
|
// RPC ping request by user
|
||||||
pingSend = true;
|
pingSend = true;
|
||||||
}
|
}
|
||||||
if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) {
|
if (pto->nPingNonceSent == 0 && pto->m_ping_start.load() + PING_INTERVAL < GetTime<std::chrono::microseconds>()) {
|
||||||
// Ping automatically sent as a latency probe & keepalive.
|
// Ping automatically sent as a latency probe & keepalive.
|
||||||
pingSend = true;
|
pingSend = true;
|
||||||
}
|
}
|
||||||
|
@ -3870,7 +3870,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
||||||
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
|
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
|
||||||
}
|
}
|
||||||
pto->fPingQueued = false;
|
pto->fPingQueued = false;
|
||||||
pto->nPingUsecStart = GetTimeMicros();
|
pto->m_ping_start = GetTime<std::chrono::microseconds>();
|
||||||
if (pto->nVersion > BIP0031_VERSION) {
|
if (pto->nVersion > BIP0031_VERSION) {
|
||||||
pto->nPingNonceSent = nonce;
|
pto->nPingNonceSent = nonce;
|
||||||
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
|
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
|
||||||
|
|
|
@ -30,7 +30,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
pch += handled;
|
pch += handled;
|
||||||
n_bytes -= handled;
|
n_bytes -= handled;
|
||||||
if (deserializer.Complete()) {
|
if (deserializer.Complete()) {
|
||||||
const int64_t m_time = std::numeric_limits<int64_t>::max();
|
const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()};
|
||||||
const CNetMessage msg = deserializer.GetMessage(Params().MessageStart(), m_time);
|
const CNetMessage msg = deserializer.GetMessage(Params().MessageStart(), m_time);
|
||||||
assert(msg.m_command.size() <= CMessageHeader::COMMAND_SIZE);
|
assert(msg.m_command.size() <= CMessageHeader::COMMAND_SIZE);
|
||||||
assert(msg.m_raw_message_size <= buffer.size());
|
assert(msg.m_raw_message_size <= buffer.size());
|
||||||
|
|
|
@ -34,7 +34,7 @@ void ProcessMessage(
|
||||||
CNode& pfrom,
|
CNode& pfrom,
|
||||||
const std::string& msg_type,
|
const std::string& msg_type,
|
||||||
CDataStream& vRecv,
|
CDataStream& vRecv,
|
||||||
int64_t nTimeReceived,
|
const std::chrono::microseconds time_received,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
ChainstateManager& chainman,
|
ChainstateManager& chainman,
|
||||||
CTxMemPool& mempool,
|
CTxMemPool& mempool,
|
||||||
|
@ -87,7 +87,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
connman.AddTestNode(p2p_node);
|
connman.AddTestNode(p2p_node);
|
||||||
g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
|
g_setup->m_node.peer_logic->InitializeNode(&p2p_node);
|
||||||
try {
|
try {
|
||||||
ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(),
|
ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, GetTime<std::chrono::microseconds>(),
|
||||||
Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool,
|
Params(), *g_setup->m_node.chainman, *g_setup->m_node.mempool,
|
||||||
g_setup->m_node.connman.get(), g_setup->m_node.banman.get(),
|
g_setup->m_node.connman.get(), g_setup->m_node.banman.get(),
|
||||||
std::atomic<bool>{false});
|
std::atomic<bool>{false});
|
||||||
|
|
|
@ -30,7 +30,10 @@ class BIP68Test(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 2
|
self.num_nodes = 2
|
||||||
self.extra_args = [
|
self.extra_args = [
|
||||||
["-acceptnonstdtxn=1"],
|
[
|
||||||
|
"-acceptnonstdtxn=1",
|
||||||
|
"-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise
|
||||||
|
],
|
||||||
["-acceptnonstdtxn=0"],
|
["-acceptnonstdtxn=0"],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,11 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [["-maxuploadtarget=800", "-acceptnonstdtxn=1"]]
|
self.extra_args = [[
|
||||||
|
"-maxuploadtarget=800",
|
||||||
|
"-acceptnonstdtxn=1",
|
||||||
|
"-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise
|
||||||
|
]]
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
||||||
# Cache for utxos, as the listunspent may take a long time later in the test
|
# Cache for utxos, as the listunspent may take a long time later in the test
|
||||||
|
|
123
test/functional/p2p_ping.py
Executable file
123
test/functional/p2p_ping.py
Executable file
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2020 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
"""Test ping message
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from test_framework.messages import (
|
||||||
|
msg_pong,
|
||||||
|
)
|
||||||
|
from test_framework.mininode import (
|
||||||
|
P2PInterface,
|
||||||
|
wait_until,
|
||||||
|
)
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import assert_equal
|
||||||
|
|
||||||
|
PING_INTERVAL = 2 * 60
|
||||||
|
|
||||||
|
|
||||||
|
class msg_pong_corrupt(msg_pong):
|
||||||
|
def serialize(self):
|
||||||
|
return b""
|
||||||
|
|
||||||
|
|
||||||
|
class NodePongAdd1(P2PInterface):
|
||||||
|
def on_ping(self, message):
|
||||||
|
self.send_message(msg_pong(message.nonce + 1))
|
||||||
|
|
||||||
|
|
||||||
|
class NodeNoPong(P2PInterface):
|
||||||
|
def on_ping(self, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PingPongTest(BitcoinTestFramework):
|
||||||
|
def set_test_params(self):
|
||||||
|
self.setup_clean_chain = True
|
||||||
|
self.num_nodes = 1
|
||||||
|
self.extra_args = [['-peertimeout=3']]
|
||||||
|
|
||||||
|
def check_peer_info(self, *, pingtime, minping, pingwait):
|
||||||
|
stats = self.nodes[0].getpeerinfo()[0]
|
||||||
|
assert_equal(stats.pop('pingtime', None), pingtime)
|
||||||
|
assert_equal(stats.pop('minping', None), minping)
|
||||||
|
assert_equal(stats.pop('pingwait', None), pingwait)
|
||||||
|
|
||||||
|
def mock_forward(self, delta):
|
||||||
|
self.mock_time += delta
|
||||||
|
self.nodes[0].setmocktime(self.mock_time)
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
self.mock_time = int(time.time())
|
||||||
|
self.mock_forward(0)
|
||||||
|
|
||||||
|
self.log.info('Check that ping is sent after connection is established')
|
||||||
|
no_pong_node = self.nodes[0].add_p2p_connection(NodeNoPong())
|
||||||
|
self.mock_forward(3)
|
||||||
|
assert no_pong_node.last_message.pop('ping').nonce != 0
|
||||||
|
self.check_peer_info(pingtime=None, minping=None, pingwait=3)
|
||||||
|
|
||||||
|
self.log.info('Reply without nonce cancels ping')
|
||||||
|
with self.nodes[0].assert_debug_log(['pong peer=0: Short payload']):
|
||||||
|
no_pong_node.send_and_ping(msg_pong_corrupt())
|
||||||
|
self.check_peer_info(pingtime=None, minping=None, pingwait=None)
|
||||||
|
|
||||||
|
self.log.info('Reply without ping')
|
||||||
|
with self.nodes[0].assert_debug_log([
|
||||||
|
'pong peer=0: Unsolicited pong without ping, 0 expected, 0 received, 8 bytes',
|
||||||
|
]):
|
||||||
|
no_pong_node.send_and_ping(msg_pong())
|
||||||
|
self.check_peer_info(pingtime=None, minping=None, pingwait=None)
|
||||||
|
|
||||||
|
self.log.info('Reply with wrong nonce does not cancel ping')
|
||||||
|
assert 'ping' not in no_pong_node.last_message
|
||||||
|
with self.nodes[0].assert_debug_log(['pong peer=0: Nonce mismatch']):
|
||||||
|
# mock time PING_INTERVAL ahead to trigger node into sending a ping
|
||||||
|
self.mock_forward(PING_INTERVAL + 1)
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
self.mock_forward(9)
|
||||||
|
# Send the wrong pong
|
||||||
|
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce - 1))
|
||||||
|
self.check_peer_info(pingtime=None, minping=None, pingwait=9)
|
||||||
|
|
||||||
|
self.log.info('Reply with zero nonce does cancel ping')
|
||||||
|
with self.nodes[0].assert_debug_log(['pong peer=0: Nonce zero']):
|
||||||
|
no_pong_node.send_and_ping(msg_pong(0))
|
||||||
|
self.check_peer_info(pingtime=None, minping=None, pingwait=None)
|
||||||
|
|
||||||
|
self.log.info('Check that ping is properly reported on RPC')
|
||||||
|
assert 'ping' not in no_pong_node.last_message
|
||||||
|
# mock time PING_INTERVAL ahead to trigger node into sending a ping
|
||||||
|
self.mock_forward(PING_INTERVAL + 1)
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
ping_delay = 29
|
||||||
|
self.mock_forward(ping_delay)
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
|
||||||
|
self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
|
||||||
|
|
||||||
|
self.log.info('Check that minping is decreased after a fast roundtrip')
|
||||||
|
# mock time PING_INTERVAL ahead to trigger node into sending a ping
|
||||||
|
self.mock_forward(PING_INTERVAL + 1)
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
ping_delay = 9
|
||||||
|
self.mock_forward(ping_delay)
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
|
||||||
|
self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
|
||||||
|
|
||||||
|
self.log.info('Check that peer is disconnected after ping timeout')
|
||||||
|
assert 'ping' not in no_pong_node.last_message
|
||||||
|
self.nodes[0].ping()
|
||||||
|
wait_until(lambda: 'ping' in no_pong_node.last_message)
|
||||||
|
with self.nodes[0].assert_debug_log(['ping timeout: 1201.000000s']):
|
||||||
|
self.mock_forward(20 * 60 + 1)
|
||||||
|
time.sleep(4) # peertimeout + 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
PingPongTest().main()
|
|
@ -236,6 +236,7 @@ BASE_SCRIPTS = [
|
||||||
'mempool_compatibility.py',
|
'mempool_compatibility.py',
|
||||||
'rpc_deriveaddresses.py',
|
'rpc_deriveaddresses.py',
|
||||||
'rpc_deriveaddresses.py --usecli',
|
'rpc_deriveaddresses.py --usecli',
|
||||||
|
'p2p_ping.py',
|
||||||
'rpc_scantxoutset.py',
|
'rpc_scantxoutset.py',
|
||||||
'feature_logging.py',
|
'feature_logging.py',
|
||||||
'p2p_node_network_limited.py',
|
'p2p_node_network_limited.py',
|
||||||
|
|
Loading…
Add table
Reference in a new issue