Compare commits

...

7 commits

Author SHA1 Message Date
Vasil Dimov
776fc5f1ef
Merge bbfc58a0af into 66aa6a47bd 2025-01-08 20:44:56 +01:00
glozow
66aa6a47bd
Merge bitcoin/bitcoin#30391: BlockAssembler: return selected packages virtual size and fee
Some checks failed
CI / test each commit (push) Has been cancelled
CI / macOS 14 native, arm64, no depends, sqlite only, gui (push) Has been cancelled
CI / macOS 14 native, arm64, fuzz (push) Has been cancelled
CI / Win64 native, VS 2022 (push) Has been cancelled
CI / Win64 native fuzz, VS 2022 (push) Has been cancelled
CI / ASan + LSan + UBSan + integer, no depends, USDT (push) Has been cancelled
7c123c08dd  miner: add package feerate vector to CBlockTemplate (ismaelsadeeq)

Pull request description:

  This PR enables `BlockAssembler` to add all selected packages' fee and virtual size to a vector, and then return the vector as a member of `CBlockTemplate` struct.

  This PR is the first step in the https://github.com/bitcoin/bitcoin/issues/30392 project.

  The packages' vsize and fee are used in #30157 to select a percentile fee rate of the top block in the mempool.

ACKs for top commit:
  rkrux:
    tACK 7c123c08dd
  ryanofsky:
    Code review ACK 7c123c08dd. Changes since last review are rebasing due to a test conflict, giving the new field a better name and description, resolving the test conflict, and renaming a lot of test variables. The actual code change is still one-line change.
  glozow:
    reACK 7c123c08dd

Tree-SHA512: 767b0b3d4273cf1589fd2068d729a66c7414c0f9574b15989fbe293f8c85cd6c641dd783cde55bfabab32cd047d7d8a071d6897b06ed4295c0d071e588de0861
2025-01-08 13:01:23 -05:00
ismaelsadeeq
7c123c08dd
miner: add package feerate vector to CBlockTemplate
- The package feerates are ordered by the sequence in which
  packages are selected for inclusion in the block template.

- The commit also tests this new behaviour.

Co-authored-by: willcl-ark <will@256k1.dev>
2025-01-07 15:29:17 -05:00
Vasil Dimov
bbfc58a0af
ci: detect outbound internet traffic generated while running tests
Resolves https://github.com/bitcoin/bitcoin/issues/31339
2025-01-06 14:35:54 +01:00
Vasil Dimov
3eb4ad7740
test: avoid generating non-loopback traffic from p2p_dns_seeds.py
`p2p_dns_seeds.py` would try to connect to the DNS server configured on
the machine and resolve `dummySeed.invalid`.

To block that configure an unavailable proxy which will be used also to
connect to the name server. The test needs 2 successful connections to
other peers (two Python `P2PInterface`s) and they work in spite of the
unavailable proxy because they are on `127.0.0.1` (`NET_UNROUTABLE`) and
the proxy is not used for that.
2025-01-06 14:35:53 +01:00
Vasil Dimov
1b3abe86f9
test: avoid generating non-loopback traffic from feature_config_args.py
`feature_config_args.py` uses a proxy address of `1.2.3.4`. This results
in actually trying to open TCP connections over the internet to
`1.2.3.4:9050`.

The test does not need those to succeed so use `127.0.0.1:1` instead.

Also avoid `-noconnect=0` because that is interpreted as `-connect=1`
which is interpreted as `-connect=0.0.0.1` and a connection to
`0.0.0.1:18444` is attempted.
2025-01-06 14:35:53 +01:00
Vasil Dimov
2eb3b8dee7
test: avoid generating non-loopback traffic from p2p_seednode.py
`p2p_seednode.py` would try to connect to `0.0.0.1` and `0.0.0.2` as
seed nodes. This sends outbound TCP packets on a non-loopback interface
to the default router.

Configure an unavailable proxy for all executions of `bitcoind` during
this test. Also change `0.0.0.1` and `0.0.0.2` because connecting to
them would skip the `-proxy=` setting because for such an address:
* `CNetAddr::IsLocal()` is true, thus
* `CNetAddr::IsRoutable()` is false, thus
* `CNetAddr::GetNetwork()` is `NET_UNROUTABLE`, even though
  `CNetAddr::m_net` is `NET_IPV4`.

This speeds up the execution time of `p2p_seednode.py`
from 12.5s to 2.5s.
2025-01-06 14:35:52 +01:00
12 changed files with 120 additions and 23 deletions

View file

@ -64,7 +64,7 @@ export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out}
# The folder for previous release binaries.
# This folder exists only on the ci guest, and on the ci host as a volume.
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/prev_releases}
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkg-config curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake}
export CI_BASE_PACKAGES=${CI_BASE_PACKAGES:-build-essential pkg-config curl ca-certificates ccache python3 rsync git procps bison e2fsprogs cmake net-tools tcpdump}
export GOAL=${GOAL:-install}
export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_SCRATCH_DIR}/qa-assets}
export CI_RETRY_EXE=${CI_RETRY_EXE:-"retry --"}

View file

@ -10,7 +10,7 @@ export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos
export CI_IMAGE_NAME_TAG="quay.io/centos/amd64:stream9"
export STREAM_GCC_V="12"
export CI_BASE_PACKAGES="gcc-toolset-${STREAM_GCC_V}-gcc-c++ glibc-devel.x86_64 gcc-toolset-${STREAM_GCC_V}-libstdc++-devel.x86_64 glibc-devel.i686 gcc-toolset-${STREAM_GCC_V}-libstdc++-devel.i686 ccache make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison e2fsprogs cmake"
export CI_BASE_PACKAGES="gcc-toolset-${STREAM_GCC_V}-gcc-c++ glibc-devel.x86_64 gcc-toolset-${STREAM_GCC_V}-libstdc++-devel.x86_64 glibc-devel.i686 gcc-toolset-${STREAM_GCC_V}-libstdc++-devel.i686 ccache make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison e2fsprogs cmake net-tools tcpdump"
export PIP_PACKAGES="pyzmq"
export GOAL="install"
export BITCOIN_CONFIG="-DWITH_ZMQ=ON -DBUILD_GUI=ON -DREDUCE_EXPORTS=ON"

View file

@ -15,3 +15,5 @@ export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DREDUCE_EXPORTS=ON"
export CI_OS_NAME="macos"
export NO_DEPENDS=1
export OSX_SDK=""
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
export CI_TCPDUMP_OK_TO_FAIL=1

View file

@ -14,3 +14,5 @@ export OSX_SDK=""
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
# Can't run tcpdump: tcpdump: en0: You don't have permission to capture on that device
export CI_TCPDUMP_OK_TO_FAIL=1

View file

@ -91,7 +91,7 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
# Append $USER to /tmp/env to support multi-user systems and $CONTAINER_NAME
# to allow support starting multiple runs simultaneously by the same user.
# shellcheck disable=SC2086
CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE $CI_CONTAINER_CAP --rm --interactive --detach --tty \
CI_CONTAINER_ID=$(docker run --cap-add LINUX_IMMUTABLE --cap-add NET_RAW $CI_CONTAINER_CAP --rm --interactive --detach --tty \
--mount "type=bind,src=$BASE_READ_ONLY_DIR,dst=$BASE_READ_ONLY_DIR,readonly" \
--mount "${CI_CCACHE_MOUNT}" \
--mount "${CI_DEPENDS_MOUNT}" \

View file

@ -146,21 +146,74 @@ if [ "$RUN_CHECK_DEPS" = "true" ]; then
"${BASE_ROOT_DIR}/contrib/devtools/check-deps.sh" .
fi
function get_interfaces()
{
set -o pipefail
ifconfig | awk -F ':| ' '/^[^[:space:]]/ { if (!match($1, /^lo/)) { print $1 } }'
set +o pipefail
}
function tcpdump_file()
{
echo "/tmp/tcpdump_$1_$2"
}
function traffic_monitor_begin()
{
test_name="$1"
for ifname in $(get_interfaces) ; do
tcpdump -nU -i "$ifname" -w "$(tcpdump_file "$test_name" "$ifname")" &
done
}
function traffic_monitor_end()
{
test_name="$1"
for ifname in $(get_interfaces) ; do
f=$(tcpdump_file "$test_name" "$ifname")
if [ ! -e "$f" ] && [ "$CI_TCPDUMP_OK_TO_FAIL" = "1" ] ; then
# In some CI environments this script is not running as root and so the
# tcpdump errors and does not create $f. Skip silently those, but we
# need at least one where tcpdump can run and this is the ASAN one. So
# treat the absence of $f as an error only on the ASAN task.
continue
fi
# We are running as root and those files are created with owner:group =
# tcpdump:tcpdump and then `tcpdump -r` refuses to read them with an error
# "permission denied" if they are not owned by root:root.
chown root:root "$f"
out="$(tcpdump -n -r "$f" --direction=out tcp or udp)"
if [ -n "$out" ] ; then
echo "Error: outbound TCP or UDP packets on the non loopback interface generated during $test_name tests:" >&2
tcpdump -n -r "$f" tcp or udp
exit 1
fi
done
}
if [ "$RUN_UNIT_TESTS" = "true" ]; then
traffic_monitor_begin "unitparallel"
DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" CTEST_OUTPUT_ON_FAILURE=ON ctest --stop-on-failure "${MAKEJOBS}" --timeout $(( TEST_RUNNER_TIMEOUT_FACTOR * 60 ))
traffic_monitor_end "unitparallel"
fi
if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
traffic_monitor_begin "unitsequential"
DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${BASE_OUTDIR}"/bin/test_bitcoin --catch_system_errors=no -l test_suite
traffic_monitor_end "unitsequential"
fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
traffic_monitor_begin "functional"
# parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"'
eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)"
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/functional/test_runner.py --ci "${MAKEJOBS}" --tmpdirprefix "${BASE_SCRATCH_DIR}"/test_runner/ --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA[@]}" --quiet --failfast
traffic_monitor_end "functional"
fi
if [ "${RUN_TIDY}" = "true" ]; then
traffic_monitor_begin "tidy"
cmake -B /tidy-build -DLLVM_DIR=/usr/lib/llvm-"${TIDY_LLVM_V}"/cmake -DCMAKE_BUILD_TYPE=Release -S "${BASE_ROOT_DIR}"/contrib/devtools/bitcoin-tidy
cmake --build /tidy-build "$MAKEJOBS"
cmake --build /tidy-build --target bitcoin-tidy-tests "$MAKEJOBS"
@ -185,9 +238,12 @@ if [ "${RUN_TIDY}" = "true" ]; then
cd "${BASE_ROOT_DIR}/src"
python3 "/include-what-you-use/fix_includes.py" --nosafe_headers < /tmp/iwyu_ci.out
git --no-pager diff
traffic_monitor_end "tidy"
fi
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
traffic_monitor_begin "fuzz"
# shellcheck disable=SC2086
LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} "${MAKEJOBS}" -l DEBUG "${DIR_FUZZ_IN}" --empty_min_time=60
traffic_monitor_end "fuzz"
fi

View file

@ -421,6 +421,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
}
++nPackagesSelected;
pblocktemplate->m_package_feerates.emplace_back(packageFees, static_cast<int32_t>(packageSize));
// Update transactions that depend on each of these
nDescendantsUpdated += UpdatePackagesForAdded(mempool, ancestors, mapModifiedTx);

View file

@ -10,6 +10,7 @@
#include <policy/policy.h>
#include <primitives/block.h>
#include <txmempool.h>
#include <util/feefrac.h>
#include <memory>
#include <optional>
@ -39,6 +40,9 @@ struct CBlockTemplate
std::vector<CAmount> vTxFees;
std::vector<int64_t> vTxSigOpsCost;
std::vector<unsigned char> vchCoinbaseCommitment;
/* A vector of package fee rates, ordered by the sequence in which
* packages are selected for inclusion in the block template.*/
std::vector<FeeFrac> m_package_feerates;
};
// Container for tracking updates to ancestor feerate as we include (parent)

View file

@ -16,6 +16,7 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/check.h>
#include <util/feefrac.h>
#include <util/strencodings.h>
#include <util/time.h>
#include <util/translation.h>
@ -25,6 +26,7 @@
#include <test/util/setup_common.h>
#include <memory>
#include <vector>
#include <boost/test/unit_test.hpp>
@ -123,19 +125,22 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
Txid hashParentTx = tx.GetHash(); // save this txid for later use
AddToMempool(tx_mempool, entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
const auto parent_tx{entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)};
AddToMempool(tx_mempool, parent_tx);
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
Txid hashMediumFeeTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
const auto medium_fee_tx{entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)};
AddToMempool(tx_mempool, medium_fee_tx);
// This tx has a high fee, but depends on the first transaction
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
Txid hashHighFeeTx = tx.GetHash();
AddToMempool(tx_mempool, entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
AddToMempool(tx_mempool, high_fee_tx);
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
BOOST_REQUIRE(block_template);
@ -145,6 +150,21 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx);
BOOST_CHECK(block.vtx[3]->GetHash() == hashMediumFeeTx);
// Test the inclusion of package feerates in the block template and ensure they are sequential.
const auto block_package_feerates = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock()->m_package_feerates;
BOOST_CHECK(block_package_feerates.size() == 2);
// parent_tx and high_fee_tx are added to the block as a package.
const auto combined_txs_fee = parent_tx.GetFee() + high_fee_tx.GetFee();
const auto combined_txs_size = parent_tx.GetTxSize() + high_fee_tx.GetTxSize();
FeeFrac package_feefrac{combined_txs_fee, combined_txs_size};
// The package should be added first.
BOOST_CHECK(block_package_feerates[0] == package_feefrac);
// The medium_fee_tx should be added next.
FeeFrac medium_tx_feefrac{medium_fee_tx.GetFee(), medium_fee_tx.GetTxSize()};
BOOST_CHECK(block_package_feerates[1] == medium_tx_feefrac);
// Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout.hash = hashHighFeeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee

View file

@ -16,6 +16,10 @@ from test_framework.test_node import ErrorMatch
from test_framework import util
# Easily unreachable address. Attempts to connect to it will stay within the machine.
# Used to avoid non-loopback traffic or DNS queries.
DUMMY_PROXY_ARG = '-proxy=127.0.0.1:1'
class ConfArgsTest(BitcoinTestFramework):
def add_options(self, parser):
self.add_wallet_options(parser)
@ -227,8 +231,8 @@ class ConfArgsTest(BitcoinTestFramework):
)
def test_log_buffer(self):
with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0\n']):
self.start_node(0, extra_args=['-noconnect=0'])
with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -listen=0\n']):
self.start_node(0, extra_args=['-nolisten=0'])
self.stop_node(0)
def test_args_log(self):
@ -259,6 +263,7 @@ class ConfArgsTest(BitcoinTestFramework):
'-rpcpassword=',
'-rpcuser=secret-rpcuser',
'-torpassword=secret-torpassword',
DUMMY_PROXY_ARG,
])
self.stop_node(0)
@ -307,7 +312,7 @@ class ConfArgsTest(BitcoinTestFramework):
],
timeout=10,
):
self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}'])
self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}', DUMMY_PROXY_ARG])
# Only regtest has no fixed seeds. To avoid connections to random
# nodes, regtest is the only network where it is safe to enable
@ -355,7 +360,7 @@ class ConfArgsTest(BitcoinTestFramework):
],
timeout=10,
):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}'])
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}', DUMMY_PROXY_ARG])
with self.nodes[0].assert_debug_log(expected_msgs=[
"Adding fixed seeds as 60 seconds have passed and addrman is empty",
]):
@ -371,18 +376,18 @@ class ConfArgsTest(BitcoinTestFramework):
# When -connect is supplied, expanding addrman via getaddr calls to ADDR_FETCH(-seednode)
# nodes is irrelevant and -seednode is ignored.
with self.nodes[0].assert_debug_log(expected_msgs=seednode_ignored):
self.start_node(0, extra_args=['-connect=fakeaddress1', '-seednode=fakeaddress2'])
self.start_node(0, extra_args=['-connect=fakeaddress1', '-seednode=fakeaddress2', DUMMY_PROXY_ARG])
# With -proxy, an ADDR_FETCH connection is made to a peer that the dns seed resolves to.
# ADDR_FETCH connections are not used when -connect is used.
with self.nodes[0].assert_debug_log(expected_msgs=dnsseed_ignored):
self.restart_node(0, extra_args=['-connect=fakeaddress1', '-dnsseed=1', '-proxy=1.2.3.4'])
self.restart_node(0, extra_args=['-connect=fakeaddress1', '-dnsseed=1', DUMMY_PROXY_ARG])
# If the user did not disable -dnsseed, but it was soft-disabled because they provided -connect,
# they shouldn't see a warning about -dnsseed being ignored.
with self.nodes[0].assert_debug_log(expected_msgs=addcon_thread_started,
unexpected_msgs=dnsseed_ignored):
self.restart_node(0, extra_args=['-connect=fakeaddress1', '-proxy=1.2.3.4'])
self.restart_node(0, extra_args=['-connect=fakeaddress1', DUMMY_PROXY_ARG])
# We have to supply expected_msgs as it's a required argument
# The expected_msg must be something we are confident will be logged after the unexpected_msg

View file

@ -10,11 +10,16 @@ from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
# Easily unreachable address. Attempts to connect to it will stay within the machine.
# Used to avoid non-loopback traffic or DNS queries.
DUMMY_PROXY_ARG = '-proxy=127.0.0.1:1'
class P2PDNSSeeds(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-dnsseed=1"]]
self.extra_args = [["-dnsseed=1", DUMMY_PROXY_ARG]]
def run_test(self):
self.init_arg_tests()
@ -29,11 +34,11 @@ class P2PDNSSeeds(BitcoinTestFramework):
self.log.info("Check that setting -connect disables -dnsseed by default")
self.nodes[0].stop_node()
with self.nodes[0].assert_debug_log(expected_msgs=["DNS seeding disabled"]):
self.start_node(0, [f"-connect={fakeaddr}"])
self.start_node(0, extra_args=[f"-connect={fakeaddr}", DUMMY_PROXY_ARG])
self.log.info("Check that running -connect and -dnsseed means DNS logic runs.")
with self.nodes[0].assert_debug_log(expected_msgs=["Loading addresses from DNS seed"], timeout=12):
self.restart_node(0, [f"-connect={fakeaddr}", "-dnsseed=1"])
self.restart_node(0, extra_args=[f"-connect={fakeaddr}", "-dnsseed=1", DUMMY_PROXY_ARG])
self.log.info("Check that running -forcednsseed and -dnsseed=0 throws an error.")
self.nodes[0].stop_node()
@ -88,7 +93,7 @@ class P2PDNSSeeds(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=["Loading addresses from DNS seed"], timeout=12):
# -dnsseed defaults to 1 in bitcoind, but 0 in the test framework,
# so pass it explicitly here
self.restart_node(0, ["-forcednsseed", "-dnsseed=1"])
self.restart_node(0, ["-forcednsseed", "-dnsseed=1", DUMMY_PROXY_ARG])
# Restore default for subsequent tests
self.restart_node(0)

View file

@ -17,22 +17,24 @@ ADD_NEXT_SEEDNODE = 10
class P2PSeedNodes(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
# Specify a non-working proxy to make sure no actual connections to random IPs are attempted.
self.extra_args = [["-proxy=127.0.0.1:1"]]
self.disable_autoconnect = False
def test_no_seednode(self):
self.log.info("Check that if no seednode is provided, the node proceeds as usual (without waiting)")
with self.nodes[0].assert_debug_log(expected_msgs=[], unexpected_msgs=["Empty addrman, adding seednode", f"Couldn't connect to peers from addrman after {ADD_NEXT_SEEDNODE} seconds. Adding seednode"], timeout=ADD_NEXT_SEEDNODE):
self.restart_node(0)
self.restart_node(0, extra_args=self.nodes[0].extra_args)
def test_seednode_empty_addrman(self):
seed_node = "0.0.0.1"
seed_node = "25.0.0.1"
self.log.info("Check that the seednode is immediately added on bootstrap on an empty addrman")
with self.nodes[0].assert_debug_log(expected_msgs=[f"Empty addrman, adding seednode ({seed_node}) to addrfetch"], timeout=ADD_NEXT_SEEDNODE):
self.restart_node(0, extra_args=[f'-seednode={seed_node}'])
self.restart_node(0, extra_args=self.nodes[0].extra_args + [f'-seednode={seed_node}'])
def test_seednode_non_empty_addrman(self):
self.log.info("Check that if addrman is non-empty, seednodes are queried with a delay")
seed_node = "0.0.0.2"
seed_node = "25.0.0.2"
node = self.nodes[0]
# Fill the addrman with unreachable nodes
for i in range(10):
@ -40,9 +42,9 @@ class P2PSeedNodes(BitcoinTestFramework):
port = 8333 + i
node.addpeeraddress(ip, port)
# Restart the node so seednode is processed again. Specify a non-working proxy to make sure no actual connections to random IPs are attempted.
# Restart the node so seednode is processed again.
with node.assert_debug_log(expected_msgs=["trying v1 connection"], timeout=ADD_NEXT_SEEDNODE):
self.restart_node(0, extra_args=[f'-seednode={seed_node}', '-proxy=127.0.0.1:1'])
self.restart_node(0, extra_args=self.nodes[0].extra_args + [f'-seednode={seed_node}'])
with node.assert_debug_log(expected_msgs=[f"Couldn't connect to peers from addrman after {ADD_NEXT_SEEDNODE} seconds. Adding seednode ({seed_node}) to addrfetch"], unexpected_msgs=["Empty addrman, adding seednode"], timeout=ADD_NEXT_SEEDNODE * 1.5):
node.setmocktime(int(time.time()) + ADD_NEXT_SEEDNODE + 1)