test: rpc: add last block announcement time to getpeerinfo result #27052

pull LarryRuane wants to merge 5 commits into bitcoin:master from LarryRuane:2023-02-getpeerinfo changing 8 files +147 −18
  1. LarryRuane commented at 6:32 PM on February 6, 2023: contributor

    This PR adds last_block_announcement to the per-peer getpeerinfo RPC result. This is the most recent time that this peer was the first to notify our node of a new block (one that we didn't already know about), or zero if this peer has never been the first to notify us of a new block. This timestamp already exists internally and is used for stale-tip eviction logic; this PR exposes it at the RPC layer.

    This PR started out as a suggestion for additional test coverage, see #26172 (comment). It turned out that the easiest way to test (already-merged) #26172 is to add this field to getpeerinfo and have a functional test verify its value. But it may also be useful to have this result in its own right, similar to that RPC's existing last_block field -- it indicates something about the quality of our peers. It allows one to predict which peer will be evicted when the stale tip logic activates. (I'm not sure if that would be useful, but it may be.)

    The functional test added here fails without #26172, which is the main goal.

    This PR does not test the actual stale-tip eviction logic; that's difficult to do with a functional test. But it does test the correctness of the timestamp that the eviction logic depends on. #23352 is an attempt to test the eviction logic using a unit test, it's not ready to be merged yet. I think having both kinds of tests would be beneficial.

  2. DrahtBot commented at 6:32 PM on February 6, 2023: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/27052.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept ACK satsie, kristapsk
    Stale ACK rkrux, naiyoma

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34833 (test: add addnode connection limit test to rpc_net.py by Bortlesboat)
    • #19461 (multiprocess: Add bitcoin-gui -ipcconnect option by ryanofsky)
    • #19460 (multiprocess: Add bitcoin-wallet -ipcconnect option by ryanofsky)
    • #10102 (Multiprocess bitcoin by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • "last_block_announcement", "The " + UNIX_EPOCH_TIME + " this peer was first to announce a block" -> "The " + UNIX_EPOCH_TIME + " of this peer was first to announce a block" [missing “of”, making the phrase grammatically incorrect and harder to parse]
    • # because its chainwork is not greater the the earlier height 2 block. -> # because its chainwork is not greater than the earlier height 2 block. [“the the” typo; missing “than” makes the comparison unclear]

    <sup>2026-04-01 21:04:11</sup>

  3. DrahtBot added the label Tests on Feb 6, 2023
  4. LarryRuane force-pushed on Feb 6, 2023
  5. LarryRuane commented at 9:52 PM on February 6, 2023: contributor

    Force pushed to fix CI failure

  6. satsie commented at 5:39 AM on February 7, 2023: contributor

    Concept ACK. I spent quite a bit of time trying to test #26172 (my findings are documented here) and can confirm the difficulty of testing it with the current state of the test framework.

    I also support the suggestion to add last_block_announcement to getpeerinfo not only because it seems to be the easiest way to test 26172, but I agree it can be useful information to have when trying to learn more about one's peers, especially when this timestamp is already available internally.

  7. in src/net.h:None in cccb498e2a outdated
     504 | @@ -505,6 +505,10 @@ class CNode
     505 |       * peer eviction criterium in CConnman::AttemptToEvictConnection. */
     506 |      std::atomic<std::chrono::seconds> m_last_block_time{0s};
     507 |  
     508 | +    /** UNIX epoch time of the last block announcement from this peer that we had
     509 | +     * not yet seen from any peer. Used for potential stale-tip eviction. */
     510 | +    std::atomic<std::chrono::seconds> m_last_block_announcement{0s};
    


    maflcko commented at 9:26 AM on February 7, 2023:

    If you change the type, why not use NodeSeconds (a time point)? While std::chrono::seconds (a duration) is used widely in the codebase, because all durations that denote a time point are since epoch, using a dedicated type such as NodeSeconds might be clearer.

  8. in src/net.h:None in becf38061b outdated
     505 | @@ -505,6 +506,10 @@ class CNode
     506 |       * peer eviction criterium in CConnman::AttemptToEvictConnection. */
     507 |      std::atomic<std::chrono::seconds> m_last_block_time{0s};
     508 |  
     509 | +    /** UNIX epoch time of the last block announcement from this peer that we had
     510 | +     * not yet seen from any peer. Used for potential stale-tip eviction. */
     511 | +    std::atomic<std::chrono::seconds> m_last_block_announcement{0s};
    


    dergoegge commented at 11:00 AM on February 7, 2023:

    I don't think this belongs in CNode. It is used in our outbound eviction logic which is part of net processing and it isn't used in net at all (imo, the eviction logic should be encapsulated in its own module entirely #25268 😉).

    Also afaict, there is no need to move m_last_block_announcement, because you can just return it in PeerManager::GetNodeStateStats.

  9. LarryRuane marked this as a draft on Feb 7, 2023
  10. DrahtBot added the label Needs rebase on May 24, 2023
  11. LarryRuane force-pushed on Aug 14, 2023
  12. DrahtBot removed the label Needs rebase on Aug 14, 2023
  13. LarryRuane force-pushed on Aug 15, 2023
  14. LarryRuane force-pushed on Aug 15, 2023
  15. DrahtBot added the label CI failed on Aug 15, 2023
  16. LarryRuane force-pushed on Aug 15, 2023
  17. LarryRuane commented at 6:55 AM on August 15, 2023: contributor

    Force pushed from becf38061b2625bcc629293fec0dce7c27292e14 to

    • efc2e70f1763c6bf3f6b246202adb9d5f1f798ee diff -- needed rebase
    • 16d2903b8a9e6e980e24e04ab2d86c7e778f5764 diff -- make the suggested review changes
    • 2e80e3bdcd9cac7878c0d14956ba9c57626da855 diff -- fix CI failure
    • 6c564aafb3d5f61fffa0d6311ad688c47b14014a diff -- add release notes, and small improvement to functional test

    I'll take this out of draft now since I think it's ready for review.

  18. LarryRuane marked this as ready for review on Aug 15, 2023
  19. DrahtBot removed the label CI failed on Aug 15, 2023
  20. in src/net_processing.cpp:None in 6c564aafb3 outdated
    5177 | @@ -5177,7 +5178,8 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
    5178 |                  // block from.
    5179 |                  CNodeState &state = *State(pnode->GetId());
    5180 |                  if (now - pnode->m_connected > MINIMUM_CONNECT_TIME && state.vBlocksInFlight.empty()) {
    5181 | -                    LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement);
    5182 | +                    LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n",
    5183 | +                             pnode->GetId(), (*oldest_block_announcement).time_since_epoch().count());
    


    maflcko commented at 12:29 PM on August 16, 2023:

    This is fragile, because when the type of oldest_block_announcement changes, the log output will change, too, without a compile error. It would be better to use Ticks or TicksSinceEpoch.


    maflcko commented at 12:29 PM on August 16, 2023:

    It is possible to write a clang-tidy check for this, but I am not sure if people want this. cc @theuni

    diff --git a/contrib/devtools/bitcoin-tidy/CMakeLists.txt b/contrib/devtools/bitcoin-tidy/CMakeLists.txt
    index 35e60d1d87..b523692b12 100644
    --- a/contrib/devtools/bitcoin-tidy/CMakeLists.txt
    +++ b/contrib/devtools/bitcoin-tidy/CMakeLists.txt
    @@ -14,7 +14,10 @@ find_program(CLANG_TIDY_EXE NAMES "clang-tidy-${LLVM_VERSION_MAJOR}" "clang-tidy
     message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
     message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
     
    -add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp logprintf.cpp)
    +add_library(bitcoin-tidy MODULE bitcoin-tidy.cpp
    +  chrono.cpp
    +  logprintf.cpp
    +)
     target_include_directories(bitcoin-tidy SYSTEM PRIVATE ${LLVM_INCLUDE_DIRS})
     
     # Disable RTTI and exceptions as necessary
    @@ -47,7 +50,10 @@ else()
     endif()
     
     # Create a dummy library that runs clang-tidy tests as a side-effect of building
    -add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL example_logprintf.cpp)
    +add_library(bitcoin-tidy-tests OBJECT EXCLUDE_FROM_ALL
    +  example_chrono.cpp
    +  example_logprintf.cpp
    +)
     add_dependencies(bitcoin-tidy-tests bitcoin-tidy)
     
     set_target_properties(bitcoin-tidy-tests PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}")
    diff --git a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
    index 0f34d37793..bc7c05ca45 100644
    --- a/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
    +++ b/contrib/devtools/bitcoin-tidy/bitcoin-tidy.cpp
    @@ -2,6 +2,7 @@
     // Distributed under the MIT software license, see the accompanying
     // file COPYING or http://www.opensource.org/licenses/mit-license.php.
     
    +#include "chrono.h"
     #include "logprintf.h"
     
     #include <clang-tidy/ClangTidyModule.h>
    @@ -12,6 +13,7 @@ class BitcoinModule final : public clang::tidy::ClangTidyModule
     public:
         void addCheckFactories(clang::tidy::ClangTidyCheckFactories& CheckFactories) override
         {
    +        CheckFactories.registerCheck<bitcoin::ChronoCheck>("bitcoin-chrono-count");
             CheckFactories.registerCheck<bitcoin::LogPrintfCheck>("bitcoin-unterminated-logprintf");
         }
     };
    diff --git a/contrib/devtools/bitcoin-tidy/chrono.cpp b/contrib/devtools/bitcoin-tidy/chrono.cpp
    new file mode 100644
    index 0000000000..163cf0b9e8
    --- /dev/null
    +++ b/contrib/devtools/bitcoin-tidy/chrono.cpp
    @@ -0,0 +1,37 @@
    +// Copyright (c) The Bitcoin Core developers
    +// Distributed under the MIT software license, see the accompanying
    +// file COPYING or https://opensource.org/license/mit/.
    +
    +#include "chrono.h"
    +
    +#include <clang/AST/ASTContext.h>
    +#include <clang/ASTMatchers/ASTMatchFinder.h>
    +
    +namespace bitcoin {
    +
    +void ChronoCheck::registerMatchers(clang::ast_matchers::MatchFinder* finder)
    +{
    +    using namespace clang::ast_matchers;
    +    
    +    finder->addMatcher(
    +        cxxMemberCallExpr(
    +            callee(cxxMethodDecl(hasName("count"))),
    +            thisPointerType(qualType(hasDeclaration(cxxRecordDecl(
    +      hasName("std::chrono::duration")
    +            )))),
    +            
    +            expr().bind("count_call")),
    +        this);
    +}
    +
    +void ChronoCheck::check(const clang::ast_matchers::MatchFinder::MatchResult& Result)
    +{
    +    if (const auto* call = Result.Nodes.getNodeAs<clang::Expr>("count_call")) {
    +        const clang::ASTContext& ctx = *Result.Context;
    +        const auto user_diag = diag(call->getEndLoc(), "Fragile call to std::chrono::duration::count(), Use Ticks or TicksSinceEpoch");
    +        //const auto& loc = call->getLocationOfByte(call->getByteLength(), *Result.SourceManager, ctx.getLangOpts(), ctx.getTargetInfo());
    +        user_diag ;//<< clang::FixItHint::CreateInsertion(loc, "\\n");
    +    }
    +}
    +
    +} // namespace bitcoin
    diff --git a/contrib/devtools/bitcoin-tidy/chrono.h b/contrib/devtools/bitcoin-tidy/chrono.h
    new file mode 100644
    index 0000000000..c455d786ed
    --- /dev/null
    +++ b/contrib/devtools/bitcoin-tidy/chrono.h
    @@ -0,0 +1,28 @@
    +// Copyright (c) The Bitcoin Core developers
    +// Distributed under the MIT software license, see the accompanying
    +// file COPYING or https://opensource.org/license/mit/.
    +
    +#ifndef CHRONO_CHECK_H
    +#define CHRONO_CHECK_H
    +
    +#include <clang-tidy/ClangTidyCheck.h>
    +
    +namespace bitcoin {
    +
    +class ChronoCheck final : public clang::tidy::ClangTidyCheck
    +{
    +public:
    +    ChronoCheck(clang::StringRef Name, clang::tidy::ClangTidyContext* Context)
    +        : clang::tidy::ClangTidyCheck(Name, Context) {}
    +
    +    bool isLanguageVersionSupported(const clang::LangOptions& LangOpts) const override
    +    {
    +        return LangOpts.CPlusPlus;
    +    }
    +    void registerMatchers(clang::ast_matchers::MatchFinder* Finder) override;
    +    void check(const clang::ast_matchers::MatchFinder::MatchResult& Result) override;
    +};
    +
    +} // namespace bitcoin
    +
    +#endif // CHRONO_CHECK_H
    diff --git a/contrib/devtools/bitcoin-tidy/example_chrono.cpp b/contrib/devtools/bitcoin-tidy/example_chrono.cpp
    new file mode 100644
    index 0000000000..1bf2f0a353
    --- /dev/null
    +++ b/contrib/devtools/bitcoin-tidy/example_chrono.cpp
    @@ -0,0 +1,18 @@
    +// Copyright (c) The Bitcoin Core developers
    +// Distributed under the MIT software license, see the accompanying
    +// file COPYING or https://opensource.org/license/mit/.
    +
    +#include <chrono>
    +
    +void good_func()
    +{
    +std::chrono::seconds a{1};
    +++a;
    +a.zero();
    +}
    +void bad_func()
    +{
    +std::chrono::seconds{1}.count();
    +std::chrono::seconds a{1};
    +a.count();
    +}
    diff --git a/src/.clang-tidy b/src/.clang-tidy
    index b4d50135dd..4deb5a85a5 100644
    --- a/src/.clang-tidy
    +++ b/src/.clang-tidy
    @@ -1,6 +1,6 @@
     Checks: '
     -*,
    -bitcoin-unterminated-logprintf,
    +bitcoin-*,
     bugprone-argument-comment,
     bugprone-use-after-move,
     misc-unused-using-decls,
    
  21. kristapsk commented at 12:40 PM on August 16, 2023: contributor

    Concept ACK

  22. LarryRuane force-pushed on Aug 16, 2023
  23. LarryRuane commented at 9:11 PM on August 16, 2023: contributor

    Force-pushed to implement review suggestion to use TicksSinceEpoch() (thanks!)

  24. DrahtBot added the label Needs rebase on Oct 3, 2023
  25. LarryRuane force-pushed on Oct 9, 2023
  26. LarryRuane force-pushed on Oct 9, 2023
  27. DrahtBot removed the label Needs rebase on Oct 9, 2023
  28. LarryRuane commented at 8:30 PM on October 9, 2023: contributor

    Force pushed for needed rebase, then again for CI failure. @dergoegge can you take another look?

  29. in src/net_processing.cpp:None in 1e11164d48 outdated
    5217 | @@ -5217,7 +5218,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
    5218 |              // If this is the only connection on a particular network that is
    5219 |              // OUTBOUND_FULL_RELAY or MANUAL, protect it.
    5220 |              if (!m_connman.MultipleManualOrFullOutboundConns(pnode->addr.GetNetwork())) return;
    5221 | -            if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) {
    5222 | +            if (!oldest_block_announcement.has_value() || (state->m_last_block_announcement == *oldest_block_announcement && pnode->GetId() > worst_peer)) {
    


    dergoegge commented at 12:34 PM on October 10, 2023:

    This looks wrong to me, i think it should be:

                if (state->m_last_block_announcement < oldest_block_announcement.value_or(NodeSeconds::max()) || (state->m_last_block_announcement == *oldest_block_announcement && pnode->GetId() > worst_peer)) {
    

    LarryRuane commented at 7:42 PM on October 10, 2023:

    Thanks, good catch! I force-pushed to fix this in a slightly different way that seems more clear to me.

  30. LarryRuane force-pushed on Oct 10, 2023
  31. DrahtBot added the label CI failed on Jan 13, 2024
  32. DrahtBot added the label Needs rebase on Jan 31, 2024
  33. LarryRuane force-pushed on Feb 13, 2024
  34. DrahtBot removed the label Needs rebase on Feb 13, 2024
  35. DrahtBot removed the label CI failed on Feb 13, 2024
  36. in test/functional/p2p_block_times.py:63 in a563827eb8 outdated
      58 | +        self.log.info("Test framework peer generates a new block")
      59 | +        tip = int(node.getbestblockhash(), 16)
      60 | +        block = create_block(tip, create_coinbase(2))
      61 | +        block.solve()
      62 | +
      63 | +        self.log.info("Test framework peer sends node the new block)")
    


    rkrux commented at 12:08 PM on March 19, 2024:

    self.log.info("Test framework peer sends node the new block)")

    Typo closing parenthesis before ending quote

  37. in doc/release-notes-27052.md:7 in b1c3826ec0 outdated
       0 | @@ -0,0 +1,7 @@
       1 | +JSON-RPC
       2 | +--------
       3 | +
       4 | +The `getpeerinfo` RPC now returns an additional result field,
       5 | +`last_block_announcement`, which indicates the most recent time
       6 | +this peer was the first to announce a new block to the local node.
       7 | +This timestamp, previously internal only, is used by the eviction logic.
    


    rkrux commented at 8:09 AM on March 20, 2024:

    Would be helpful to mention which kind of eviction does this refer to.


    rkrux commented at 8:15 AM on March 20, 2024:

    stale-tip eviction logic

  38. rkrux approved
  39. rkrux commented at 8:24 AM on March 20, 2024: contributor

    ACK b1c3826

    Testing Methodology

    1. Checked out PR
    2. Built core
    3. Ran make check
    4. Ran test/functional/test_runner.py.
    5. Ran bitcoind
    6. Ran bcli getpeerinfo | jq '.[] | .last_block_announcement' & got the following output that shows the presence of this new field last_block_announcement for nodes sending out new blocks to my node, 0 for the rest.
    1710919881
    0
    1710919901
    1710920179
    0
    0
    0
    0
    0
    0
    

    Note: This functional/feature_anchors.py test did fail one time before it passed on the re-run, which I guess is due to unrelated error. PFB the error output.

    stdout:
    2024-03-20T07:07:27.561000Z TestFramework (INFO): PRNG seed is: 4633686694814387857
    2024-03-20T07:07:27.562000Z TestFramework (INFO): Initializing test directory /var/folders/6v/mpspb4bx4zzf3xr2z96hgq9h0000gn/T/test_runner_₿_🏃_20240320_122543/feature_anchors_23
    2024-03-20T07:07:28.673000Z TestFramework (INFO): When node starts, check if anchors.dat doesn't exist
    2024-03-20T07:07:28.673000Z TestFramework (INFO): Add 2 block-relay-only connections to node
    2024-03-20T07:07:28.942000Z TestFramework (INFO): Add 5 inbound connections to node
    2024-03-20T07:07:29.682000Z TestFramework (INFO): Check node connections
    2024-03-20T07:07:30.121000Z TestFramework (INFO): Check the addresses in anchors.dat
    2024-03-20T07:07:30.122000Z TestFramework (INFO): Perturb anchors.dat to test it doesn't throw an error during initialization
    2024-03-20T07:07:30.748000Z TestFramework (INFO): When node starts, check if anchors.dat doesn't exist anymore
    2024-03-20T07:07:30.748000Z TestFramework (INFO): Ensure addrv2 support
    2024-03-20T07:07:32.108000Z TestFramework (INFO): Add 256-bit-address block-relay-only connections to node
    2024-03-20T07:07:32.761000Z TestFramework (INFO): Check for addrv2 addresses in anchors.dat
    2024-03-20T07:07:32.845000Z TestFramework (INFO): Restarting node attempts to reconnect to anchors
    2024-03-20T07:07:34.928000Z TestFramework (ERROR): Assertion failed
    
    AssertionError: [node 0] Expected messages "['Trying to make an anchor connection to pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333']" does not partially match log:
    
  40. LarryRuane force-pushed on Mar 21, 2024
  41. LarryRuane commented at 5:48 PM on March 21, 2024: contributor

    @rkrux - Thanks for the review and the suggestions, force-pushed them.

  42. DrahtBot added the label Needs rebase on Apr 30, 2024
  43. LarryRuane force-pushed on May 1, 2024
  44. DrahtBot removed the label Needs rebase on May 1, 2024
  45. DrahtBot added the label Needs rebase on Jul 24, 2024
  46. LarryRuane force-pushed on Jul 26, 2024
  47. DrahtBot removed the label Needs rebase on Jul 26, 2024
  48. naiyoma commented at 6:45 PM on August 19, 2024: contributor

    Concept ACK , Adding last_block_announcement field to the getpeerinfo RPC result is a valuable addition.

  49. in test/functional/p2p_block_times.py:None in c49b1097b3 outdated
      57 | +
      58 | +        self.log.info("Test framework peer generates a new block")
      59 | +        tip = int(node.getbestblockhash(), 16)
      60 | +        block = create_block(tip, create_coinbase(2))
      61 | +        block.solve()
      62 | +
    


    naiyoma commented at 7:11 PM on August 29, 2024:

    nit: I think it would be useful to add an assertion to check the initial value of last_block_announcement

       self.log.info("Check that last_block_announcement is initially zero")
            peerinfo = node.getpeerinfo()[0]
            assert peerinfo['last_block_announcement'] == 0
    
    
  50. naiyoma commented at 12:01 PM on August 30, 2024: contributor

    I tested to check if functional tests fail without the change from https://github.com/bitcoin/bitcoin/pull/26172/

    Reverted this commit https://github.com/bitcoin/bitcoin/commit/9fcdb9f3a044330d3d7515fa35709102c98534d2 make clean ./configure make

    The test fails as expected

    assert peerinfo['last_block_announcement'] == cur_time
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AssertionError
    

    last_block_announcement doesn't get updated instead value is always default 0

  51. DrahtBot added the label Needs rebase on Sep 2, 2024
  52. LarryRuane force-pushed on Sep 9, 2024
  53. DrahtBot removed the label Needs rebase on Sep 9, 2024
  54. DrahtBot added the label CI failed on Sep 12, 2024
  55. DrahtBot added the label Needs rebase on Sep 13, 2024
  56. LarryRuane force-pushed on Sep 17, 2024
  57. DrahtBot removed the label Needs rebase on Sep 17, 2024
  58. DrahtBot removed the label CI failed on Sep 17, 2024
  59. DrahtBot added the label Needs rebase on Oct 29, 2024
  60. LarryRuane force-pushed on Nov 2, 2024
  61. DrahtBot removed the label Needs rebase on Nov 2, 2024
  62. DrahtBot added the label CI failed on Dec 27, 2024
  63. DrahtBot removed the label CI failed on Jan 1, 2025
  64. DrahtBot added the label CI failed on Mar 19, 2025
  65. DrahtBot commented at 6:42 PM on March 19, 2025: contributor

    Needs rebase, if still relevant

  66. LarryRuane force-pushed on Mar 31, 2025
  67. LarryRuane commented at 11:02 PM on March 31, 2025: contributor

    Rebased for merge conflicts and to adopt @naiyoma's review suggestion (thank you!).

  68. DrahtBot removed the label CI failed on Mar 31, 2025
  69. DrahtBot added the label Needs rebase on Apr 25, 2025
  70. LarryRuane force-pushed on Apr 29, 2025
  71. DrahtBot removed the label Needs rebase on Apr 29, 2025
  72. DrahtBot added the label CI failed on Apr 29, 2025
  73. LarryRuane force-pushed on Apr 30, 2025
  74. DrahtBot removed the label CI failed on Apr 30, 2025
  75. DrahtBot added the label CI failed on May 19, 2025
  76. DrahtBot removed the label CI failed on May 21, 2025
  77. luke-jr referenced this in commit 8e344835b5 on Jun 6, 2025
  78. luke-jr referenced this in commit a4e4e17feb on Jun 6, 2025
  79. luke-jr referenced this in commit 01a7caefac on Jun 6, 2025
  80. luke-jr referenced this in commit 5a3a595459 on Jun 6, 2025
  81. in test/functional/p2p_block_times.py:None in f7788f66b4 outdated
      16 | +This timestamp is used when the "potential stale tip" condition occurs:
      17 | +When a new block hasn't been seen for a longer-than-expected amount of
      18 | +time (currently 30 minutes, see TipMayBeStale()), the client, suspecting
      19 | +that there may be new blocks that its peers are not announcing, will
      20 | +add an extra outbound peer and disconnect (evict) the peer that has
      21 | +least recently been the first to announced a new block to us. (If there
    


    DrahtBot commented at 8:36 AM on June 25, 2025:

    first to announced a new block → first to announce a new block

  82. LarryRuane force-pushed on Jul 1, 2025
  83. in src/net_processing.cpp:5192 in 3d961ebdd9 outdated
    5188 | @@ -5189,7 +5189,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
    5189 |          // Protect peers from eviction if we don't have another connection
    5190 |          // to their network, counting both outbound-full-relay and manual peers.
    5191 |          NodeId worst_peer = -1;
    5192 | -        int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
    5193 | +        std::optional<NodeSeconds> oldest_block_announcement;
    


    naiyoma commented at 8:26 PM on August 19, 2025:

    I'm not sure I understand why this is optional. Originally, it was set to a sentinel value. I don't see a situation where it wouldn't have a value. My suggestion → NodeSeconds oldest_block_announcement = NodeSeconds::max(); That way .has_value() checks and *oldest_block_announcement can be avoided.


    theuni commented at 8:41 PM on August 19, 2025:

    optional + has_value() communicates intent much more clearly than the sentinel imo. Though admittedly it's awkward as long as worst_peer uses a sentinel as well.

    I'd expect to see std::optional<std::pair<NodeId, NodeSeconds>> worst_peer, personally.

  84. naiyoma commented at 1:39 PM on August 22, 2025: contributor

    Tested ACK cbe4603a90220f0ef0b21c4da68ee16791ad9034

    Changes since last review: rebased and addressed nit fixes.

    Also tested with msg_cmpctblock - test passed as expected.

  85. DrahtBot requested review from rkrux on Aug 22, 2025
  86. DrahtBot added the label Needs rebase on Feb 7, 2026
  87. LarryRuane force-pushed on Feb 10, 2026
  88. DrahtBot removed the label Needs rebase on Feb 10, 2026
  89. DrahtBot added the label CI failed on Feb 10, 2026
  90. DrahtBot closed this on Feb 12, 2026

  91. ?
    project_v2_item_status_changed github-project-automation[bot]
  92. ?
    project_v2_item_status_changed github-project-automation[bot]
  93. DrahtBot reopened this on Feb 12, 2026

  94. DrahtBot removed the label CI failed on Feb 12, 2026
  95. sedited requested review from naiyoma on Mar 3, 2026
  96. sedited requested review from dergoegge on Mar 3, 2026
  97. sedited removed review request from naiyoma on Mar 3, 2026
  98. sedited removed review request from rkrux on Mar 3, 2026
  99. sedited requested review from rkrux on Mar 3, 2026
  100. sedited requested review from naiyoma on Mar 3, 2026
  101. sedited commented at 8:08 AM on March 11, 2026: contributor

    @rkrux @naiyoma can you take another look here?

  102. rkrux commented at 11:49 AM on March 12, 2026: contributor

    can you take another look here?

    Will get around to it soon.

  103. dergoegge commented at 12:05 PM on March 12, 2026: member

    I think the commit messages for the last two commits should be more detailed

  104. sedited removed review request from naiyoma on Mar 12, 2026
  105. sedited requested review from danielabrozzoni on Mar 12, 2026
  106. LarryRuane force-pushed on Mar 13, 2026
  107. in test/functional/p2p_block_times.py:71 in b569561910
      66 | +        block = create_block(tip, create_coinbase(2))
      67 | +        block.solve()
      68 | +
      69 | +        self.log.info("Check that last_block_announcement is initially zero")
      70 | +        peerinfo = node.getpeerinfo()[0]
      71 | +        assert peerinfo['last_block_announcement'] == 0
    


    danielabrozzoni commented at 8:12 PM on March 18, 2026:

    Here and below: prefer using assert_equal over assert, since it gives better error messages on failure.

    See for example #34773 for some effort in that direction

  108. in test/functional/p2p_block_times.py:25 in b569561910
      20 | +add an extra outbound peer and disconnect (evict) the peer that has
      21 | +least recently been the first to announce a new block to us. (If there
      22 | +is a tie, it will disconnect the most recently-added of those peers.)
      23 | +
      24 | +This test verifies that this timestamp is being set correctly.
      25 | +(This tests PR 26172.)
    


    danielabrozzoni commented at 8:20 PM on March 18, 2026:

    nit: we usually put the github link instead of the PR number, so it can be clicked directly:

    ❯ git grep "github.com/bitcoin/bitcoin/pull" test/functional/
    
    test/functional/README.md:  The CI linter job also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
    test/functional/feature_assumevalid.py:valid (https://github.com/bitcoin/bitcoin/pull/9484)
    test/functional/feature_notifications.py:            # [#9371](/bitcoin-bitcoin/9371/), it might be better
    test/functional/rpc_decodescript.py:        # Sourced from [#27037 (comment)](/bitcoin-bitcoin/27037/#issuecomment-1416151907).
    test/functional/rpc_rawtransaction.py:        # Do this with a pruned chain, as a regression test for [#29003](/bitcoin-bitcoin/29003/)
    test/functional/test_runner.py:    # a hard link or a copy on any platform. See [#27561](/bitcoin-bitcoin/27561/).
    test/functional/tool_bitcoin.py:        # [#33229 (comment)](/bitcoin-bitcoin/33229/#issuecomment-3265524908)
    
  109. in src/net_processing.cpp:5417 in 56cd8d9160
    5413 | @@ -5413,7 +5414,7 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
    5414 |                  CNodeState &state = *State(pnode->GetId());
    5415 |                  if (now - pnode->m_connected > MINIMUM_CONNECT_TIME && state.vBlocksInFlight.empty()) {
    5416 |                      LogDebug(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n",
    5417 | -                             pnode->GetId(), (*oldest_block_announcement).time_since_epoch().count());
    5418 | +                             pnode->GetId(), TicksSinceEpoch<std::chrono::seconds>(*oldest_block_announcement));
    


    danielabrozzoni commented at 10:49 PM on March 18, 2026:

    In 56cd8d9160fe31c6cef15db6ef501f7bebdb36ac: I think this line is a cleanup that should be in the first commit, not in this one

  110. in test/functional/p2p_block_times.py:51 in b569561910
      46 | +
      47 | +class P2PBlockTimes(BitcoinTestFramework):
      48 | +    def set_test_params(self):
      49 | +        self.setup_clean_chain = True
      50 | +        self.num_nodes = 1
      51 | +        self.disable_autoconnect = False
    


    danielabrozzoni commented at 11:02 PM on March 18, 2026:

    Why is this needed?


    LarryRuane commented at 4:52 AM on April 2, 2026:

    You're correct, the last of those 3 lines (self.disable_autoconnect = False) doesn't appear to be needed; I don't remember where I got it from (another test, probably). Removed, thanks.

  111. in test/functional/p2p_block_times.py:62 in b569561910
      57 | +
      58 | +        # Generate one block to exit IBD
      59 | +        self.generate(node, 1)
      60 | +
      61 | +        self.log.info("Create a full-outbound test framework peer")
      62 | +        node.add_outbound_p2p_connection(P2PDataStore(), p2p_idx=0)
    


    danielabrozzoni commented at 11:04 PM on March 18, 2026:

    nit: The pattern in other functional tests is to save the connection object and use it, instead of using p2ps:

    diff --git a/test/functional/p2p_block_times.py b/test/functional/p2p_block_times.py
    index 6fc60f629e..7fba2ad212 100755
    --- a/test/functional/p2p_block_times.py
    +++ b/test/functional/p2p_block_times.py
    @@ -59,7 +59,7 @@ class P2PBlockTimes(BitcoinTestFramework):
             self.generate(node, 1)
     
             self.log.info("Create a full-outbound test framework peer")
    -        node.add_outbound_p2p_connection(P2PDataStore(), p2p_idx=0)
    +        peer = node.add_outbound_p2p_connection(P2PDataStore(), p2p_idx=0)
     
             self.log.info("Test framework peer generates a new block")
             tip = int(node.getbestblockhash(), 16)
    @@ -71,7 +71,7 @@ class P2PBlockTimes(BitcoinTestFramework):
             assert peerinfo['last_block_announcement'] == 0
     
             self.log.info("Test framework peer sends node the new block")
    -        node.p2ps[0].send_blocks_and_test([block], node, success=True)
    +        peer.send_blocks_and_test([block], node, success=True)
     
             self.log.info("Verify peerinfo block timestamps")
             peerinfo = node.getpeerinfo()[0]
    @@ -82,7 +82,7 @@ class P2PBlockTimes(BitcoinTestFramework):
             node.setmocktime(cur_time+1)
             headers_message = msg_headers()
             headers_message.headers = [CBlockHeader(block)]
    -        node.p2ps[0].send_and_ping(headers_message)
    +        peer.send_and_ping(headers_message)
     
             self.log.info("Verify that block announcement time isn't updated")
             peerinfo = node.getpeerinfo()[0]
    

    However, some tests still use node.p2ps... If you like it better, feel free to keep it as is

  112. danielabrozzoni commented at 11:20 PM on March 18, 2026: member

    Code Review d46a3a5cce4122c09a5b302dfec997e68ee9698d

    I still haven't tested, I only looked at the code for now. The code looks ok, but there are some style improvements that I think should be picked up:

    • I would like to see #27052 (review), I think it would make the code more consistent and easier to understand
    • In the first commit (e3ea5366cd5182525089cfd1a55dc675ff5faa46), it would be nice to have some more context in the commit message on why you're converting m_last_block_announcement to NodeSeconds. Something as easy as "preparatory for next commit" is fine, it's just to have some history in git as well
    • The PR description is good and gives a lot of insight as of why the PR is useful, but this context should be in the commit messages as well. I would add it to the commit message of the third commit (34b9122c2046f55901d3ccdcf9532f23e0c1326c)
    • The first three commits should have the prefixes rpc: or net: in the commit message.
  113. naiyoma commented at 1:05 PM on March 20, 2026: contributor

    TestedACK d46a3a5cce4122c09a5b302dfec997e68ee9698d

    Tested without the fix from PR #26172 by flipping the null check condition. The test fails as expected, catching last_block_announcement not being updated when a peer announces a new block.

    assert peerinfo['last_block_announcement'] == cur_time
    AssertionError
    

    I have not been able to observe any eviction logs, but I could see the last_block_announcement being set for my peers Every 5.0s: bitcoin-cli getpeerinfo | grep last_block_announcement ubuntu: Fri Mar 20 12:46:28 2026

    "last_block_announcement": 1773995600,
    "last_block_announcement": 0,
    "last_block_announcement": 0,
    "last_block_announcement": 1773999976,
    "last_block_announcement": 1773999593,
    "last_block_announcement": 0,
    "last_block_announcement": 1773997866,
    "last_block_announcement": 0,

    micro nits: you can address this if you have to make another push

    Consider adding a test case for when a peer sends a header that is new to us but has less chain work than our tip last_block_announcement.

  114. LarryRuane force-pushed on Mar 30, 2026
  115. LarryRuane force-pushed on Mar 31, 2026
  116. DrahtBot added the label CI failed on Mar 31, 2026
  117. change m_last_block_announcement type from int64_t to NodeSeconds
    This non-functional change makes it clear that this variable is a
    time_point (point-in-time) rather than a duration. (An int64_t can be
    either). This variable's use is modified in the following commits, so
    we may as well moderize its type. This type is also mockable, which a
    later test commit takes advantage of.
    a0939e6802
  118. net: add m_last_block_announcement to CNodeStateStats
    Copy its value from CNodeState. Unused until the next commit.
    1e64825bd1
  119. rpc: add last_block_announcement to the getpeerinfo output
    This is the most recent time that this peer was the first to notify our
    node of a new block (one that we didn't already know about), or zero if
    this peer has never been the first to notify us of a new block. This can
    be used to evaluate the quality (performance) of this peer, similar to
    the existing `last_block` field.
    
    This timestamp already exists internally and is used for stale-tip
    eviction logic; this PR exposes it at the RPC layer. This will also be
    used (in a later commit) to increase stale-tip test coverage.
    f506757a49
  120. test: add functional test for block announcement time tracking 168484e4e4
  121. doc: add release note for 27052
    The `getpeerinfo` RPC now returns `last_block_announcement`.
    036a87b8a9
  122. LarryRuane force-pushed on Apr 1, 2026
  123. LarryRuane commented at 9:05 PM on April 1, 2026: contributor

    I think I've addressed (and accepted) all suggestions, thanks!

  124. naiyoma commented at 12:01 PM on April 2, 2026: contributor

    I think I've addressed (and accepted) all suggestions, thanks!

    will re-review

    I haven't been able to reproduce the test failing

    458/458 - p2p_block_times.py failed, Duration: 2401 s

    I think this is where the timeout is happening -> https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/p2p.py#L917


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-15 03:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me