Skip to content

[Bug] Duplicates on AddrMan #853

Description

@jaoleal

Describe the bug

While reviewing #781 I found a bug that could exhaust device resources for long runs, I decided to write this issue instead of a pr comment because it got too verbose.

Seeing that push_if_has_service is being called 3 times in a row for the same LocalAddress i started thinking if there was any dedup going on... I saw that push_addresses does check duplicates but push_if_has_service does not.

so i added the below here on address_man:422 inside the prune_addresses method, which is called evey push_address

        // Print duplicates 
        for (service, peers) in &self.peers_by_service { // iterate over piers
           // cast them into a HashSet, a hashset should not retain any duplicates.
            let unique: std::collections::HashSet<&usize> = peers.iter().collect();
            // print when their length mismatch
             if peers.len() != unique.len() {
                println!(
                    "  DUPLICATES in peers_by_service[{:?}]: total={} unique={}",
                    service,
                    peers.len(),
                    unique.len()
                );
            }
        }

        for (service, peers) in &self.good_peers_by_service {
            // cast them into a HashSet, a hashset should not retain any duplicates.
            let unique: std::collections::HashSet<&usize> = peers.iter().collect();
            // print when their length mismatch
            if peers.len() != unique.len() {
                println!(
                    "  DUPLICATES in good_peers_by_service[{:?}]: total={} unique={}",
                    service,
                    peers.len(),
                    unique.len()
                );
            }
        }

        println!(
            "prune_addresses called: total={} max={} excess={}",
            self.addresses.len(),
            self.max_size,
            excess
        );

When running florestad in a normal run, e.g. cargo run --bin florestad, i could already see:

2026-02-21 17:57:17  INFO floresta_wire::p2p_wire::node::chain_selector_ctx: Downloading headers from peer=0 at height=24001 hash=00000000057136237ef09824c432d8151cc23bcb009cecf49ace17003fe574be
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=1742 unique=1740
prune_addresses called: total=1740 max=50000 excess=0
2026-02-21 17:57:17 ERROR floresta_wire::p2p_wire::node::chain_selector_ctx: 798: crates/floresta-wire/src/p2p_wire/node/chain_selector_ctx.rs - NoPeersAvailable
2026-02-21 17:57:38  INFO floresta_wire::p2p_wire::node::peer_man: New peer id=4 version=/Satoshi:30.0.0/ blocks=937711 services=ServiceFlags(NETWORK|WITNESS|COMPACT_FILTERS|NETWORK_LIMITED|P2P_V2)
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=1064 unique=1063
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=2300 unique=2296
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=358 unique=357
prune_addresses called: total=2296 max=50000 excess=0
2026-02-21 17:58:00  INFO floresta_wire::p2p_wire::node::peer_man: New peer id=7 version=/Satoshi:30.0.0/ blocks=937711 services=ServiceFlags(NETWORK|BLOOM|WITNESS|COMPACT_FILTERS|NETWORK_LIMITED|P2P_V2)
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=1301 unique=1299
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=2828 unique=2823
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=357 unique=356
prune_addresses called: total=2823 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=1302 unique=1300
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=2830 unique=2825
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=357 unique=356
prune_addresses called: total=2825 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=1302 unique=1300
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=2830 unique=2825
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=356 unique=355
prune_addresses called: total=2825 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=1303 unique=1301
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=2831 unique=2826
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=355 unique=354
prune_addresses called: total=2826 max=50000 excess=0

the duplicates continue to grow:

prune_addresses called: total=8252 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=3673 unique=3665
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=8268 unique=8252
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=1119 unique=1117
  DUPLICATES in good_peers_by_service[ServiceFlags(64)]: total=453 unique=452
prune_addresses called: total=8252 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=3673 unique=3665
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=8268 unique=8252
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=1119 unique=1117
  DUPLICATES in good_peers_by_service[ServiceFlags(64)]: total=453 unique=452
prune_addresses called: total=8252 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=3673 unique=3665
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=8268 unique=8252
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=1119 unique=1117
  DUPLICATES in good_peers_by_service[ServiceFlags(64)]: total=453 unique=452
prune_addresses called: total=8252 max=50000 excess=0
  DUPLICATES in peers_by_service[ServiceFlags(64)]: total=3673 unique=3665
  DUPLICATES in peers_by_service[ServiceFlags(0)]: total=8268 unique=8252
  DUPLICATES in good_peers_by_service[ServiceFlags(0)]: total=1119 unique=1117
  DUPLICATES in good_peers_by_service[ServiceFlags(64)]: total=453 unique=452
prune_addresses called: total=8252 max=50000 excess=0

therefore, when i add the code below on address_man:511 at the beginning of push_if_has_service.

        // don't add duplicate addresses
        if self
            .addresses
            .values()
            .any(|x| x.address == address.address)
        {
            return;
        }

And by restarting florestad I could see the behavior to change:

2026-02-21 18:21:08  INFO floresta_wire::p2p_wire::node::conn: Fetched 347 peer addresses from all DNS seeds
prune_addresses called: total=8299 max=50000 excess=0
2026-02-21 18:21:07  INFO floresta_wire::p2p_wire::address_man: Fetched 39 peer addresses from DNS host: x9.dnsseed.emzy.de
2026-02-21 18:21:08  INFO floresta_wire::p2p_wire::address_man: Fetched 31 peer addresses from DNS host: x49.seed.bitcoin.wiz.biz
2026-02-21 18:21:08  INFO floresta_wire::p2p_wire::address_man: Fetched 31 peer addresses from DNS host: x9.seed.bitcoin.wiz.biz
2026-02-21 18:21:08  INFO floresta_wire::p2p_wire::node::conn: Fetched 347 peer addresses from all DNS seeds
prune_addresses called: total=8299 max=50000 excess=0
22026-02-21 18:22:24  INFO floresta_wire::p2p_wire::node::peer_man: New peer id=9 version=/Satoshi:30.2.0/ blocks=937712 services=ServiceFlags(NETWORK|WITNESS|NETWORK_LIMITED|P2P_V2)
prune_addresses called: total=8984 max=50000 excess=0
2026-02-21 18:22:25  INFO floresta_wire::p2p_wire::node::chain_selector_ctx: Downloading headers from peer=9 at height=26001 hash=000000006aee625129fc9ad7ba7930b89c80ebf22ce4448d5ebdd8609fdf0a3d

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions