Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions Kip-0019.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
```
KIP: 0019
Layer: Routing, Networking, P2P, Node
Title: Inbound Peer Eviction Policy
Author: D-Stakes
Status: Draft
Created: 2026-01-07
```

This document specifies an inbound peer eviction policy and logic for Kaspa nodes.

# Motivation

When a node's inbound peer set exceeds its configured limit, it must disconnect peers. The current randomized eviction is vulnerable to eclipse attacks: a Sybil attacker can repeatedly request inbound connections, relying on random eviction to gradually replace honest peers.

While a node's outbound connections remain the primary defense against eclipse attacks, a sophisticated eviction policy for inbound peers can increase overall resilience.

This policy is inspired by Bitcoin Core's eviction approach: protect peers with diverse, difficult-to-forge characteristics, and evict based on non-latency performance metrics.

**Goals:**
- Reduce the probability that one entity dominates a node's inbound peer set
- Maintain diversity across network locations utilizing IP prefix bucketing
- Prefer stable, long-connected peers
- Prefer peers that contribute blocks/transactions
- Avoid systematically excluding disadvantaged high-latency peers
- Slow-down connection spamming success-rates.

# Specification

## Definitions

- **Inbound limit** (`L`): Maximum allowed inbound peers
- **Active inbound set** (`P`): Current inbound peers, with size `N = |P|`
- **Overflow**: `max(0, N - L)` — when positive, exactly this many peers must be evicted

## Peer Attributes

For each inbound peer `p`, the node tracks:

| Attribute | Description |
|-----------|-------------|
| `uptime(p)` | Duration since connection |
| `ping(p)` | Most recent ping RTT |
| `block_ts(p)` | Last block transfer timestamp (optional) |
| `tx_ts(p)` | Last transaction transfer timestamp (optional) |
| `bucket(p)` | IP prefix bucket |

## Prefix Buckets

Each peer is assigned a bucket derived from its IP address:

- **IPv4**: First two octets (`/16` prefix)
- **IPv6**: First eight octets (`/64` prefix)
- **IPv4-mapped IPv6**: Use IPv4 rule

The node computes `count[b]` — the number of peers in each bucket — per eviction cycle.

## Metrics

Peers are ranked on five metrics. Lower rank = better. Ties share the average rank.

| Metric | Preference | Rank rule |
|--------|------------|-----------|
| Prefix concentration | Sparse buckets | Higher `count[bucket(p)]` → worse rank |
| Uptime | Longer | Shorter `uptime(p)` → worse rank |
| Ping RTT | Lower | Higher `ping(p)` → worse rank |
| Block transfer | Recent | Missing or older `block_ts(p)` → worse rank |
| Transaction transfer | Recent | Missing or older `tx_ts(p)` → worse rank |

**note:** Considering kaspa's high throughput raw last transfered `block_ts` and `tx_ts`, may not be an ideal metric, potentially using averages, or counts, may be a better metric. none-the-less `last transfer`, is easy and cheap to implement and track, and should at the very least act as a proxy for closeness to tx / block producing parts of the network. But alternatives may be considered here.

## Classification

**Latency-correlated metrics:** ping, block transfer, transaction transfer

**Non-latency metrics:** uptime, prefix concentration

## Eviction Procedure

### Stage 1: Protected Set

Protect the top 40% of peers (by inbound limit):

```
retain_count = floor(L * 0.4)
```

Each peer's "best rank" is the minimum across all five metrics:

```
best(p) = min(rank_bucket, rank_uptime, rank_ping, rank_block, rank_tx)
```

Sort peers by ascending `best(p)`, breaking ties randomly. The first `retain_count` peers are protected and cannot be evicted.

**Note:** Due to the nature of ranked variables not being duplicatable (beyond tie breaking), The min function and sorting used here implictly diversifies the metrics used.

### Stage 2: Weighted Random Eviction

From the remaining unprotected peers, evict exactly `N - L` peers using weighted random sampling without replacement.

The weight uses only non-latency metrics:

```
worst_non_latency(p) = max(rank_uptime, rank_bucket)
weight(p) = 1 + worst_non_latency(p)
```

Higher weight → more likely to be evicted.

## Eviction Action

Selected peers are disconnected immediately.

# Rationale

**Multi-signal protection:** Protecting peers exceptional in *any* dimension limits attackers who can only optimize one metric cheaply.

**Prefix diversity:** Biasing eviction toward crowded buckets maintains geographic and ownership diversity.

**Non-latency eviction weights:** Using only uptime and bucket concentration for eviction weighting avoids penalizing high-latency, but otherwise valuable, peers, while pressuring connection spam and prefix concentration.

**Random tie-breaking:** Reduces predictability and information leakage.

# Security Considerations

## Pros:

**Stage 1:** Protect a diverse set of peers, accross different metrics
1. Establish nodes with good ping (geographic proximity)
2. Position near block producers and transaction sources
3. Maintain long uptime toward the target
4. Disperse connections across multiple IP prefixes

**Result**

To eclipse protected peers, an adversary must carefully construct an artificial network around the target node — one that mimics and ultimately outperforms the strongest participants in a natural Gaussian distribution, on a wide array of independent variables.

**Stage 2:** Connection Spam Resistance

Preliminary statistical analysis conducted also demonstrates the effectiveness of this defense. For an unprotected peer set of 77 peers (corresponding to an inbound limit of 128 peers), assuming heterogeneous prefix distribution and consecutive uptime ranks:

| Eviction Policy | Mean Attempts to Replace All Peers | First-Attempt Self-Eviction Rate |
|-----------------|-----------------------------------|----------------------------------|
| Random eviction | 379.4 | 1.3% |
| Weighted eviction (this KIP) | 2,248 | 2.5% |

**Result**

- The weighted eviction policy requires approximately **6× more connection attempts** for an adversary to replace all unprotected peers
- The self-eviction rate for honest peers (i.e. on first attempt eviction) increases only marginally (from 1.3% to 2.5%) **2x more liklyhood**
- Furthermore, without diverse IP prefix bucketing, attackers will probabilistically evict their own connections with even more liklyhood, making sustained spam attacks significantly more resource-intensive

**Note:** By multiplying these weights by some multiplier, this mechnisim can be fine tuned to increase, or decrease spam protection, which potentially can be used to fine-tune this mechanisim, for example when the node "thinks" it is under a spam attack.

## Cons

- Prefix saturation attacks can increase churn and decrease connection availability for honest peers in the same prefix, i.e. instead of targeting the node directly, an adversary can try and establish a large amount of nodes within the same prefix as a target, thereby making it more difficult for the target to gain reliable access to the network. This might particularly be problematic for prefixes belonging to known hosting providers, where it becomes easy to establish oneself in the same prefix.

# Backwards Compatibility

This policy changes behavior only when inbound connections exceed the limit. No protocol changes required.

# Disclaimer

This KIP was partially AI-generated.

# Reference Implementation

[kaspanet/rusty-kaspa#431](https://github.com/kaspanet/rusty-kaspa/pull/431)

# References

- Heilman et al., "Eclipse Attacks on Bitcoin's Peer-to-Peer Network", USENIX Security 2015
- Bitcoin Core eviction: [src/node/eviction.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/node/eviction.cpp)