seeding lies

Exposing the auction beneath file sharing and demonstrating that fairness maintains performance

June 2025Read Full PostBitTorrentPropShare+4

Shounak Ray, Yousef AbuHashem, Fabio Ibanez, and Jacob Roberts-Baca


The Quick Version

BitTorrent isn't what everyone thought it was. For years, people believed it used "tit-for-tat" to encourage fair sharing. Upload to others, they upload to you. Simple reciprocity.

One way to view the protocol is through the lens of an auction. Peers bid for bandwidth by uploading data, and the highest bidders win—but once you win, you get equal share regardless of your bid. This creates a perverse incentive: contribute just enough to stay in the top tier, but no more.

This results in exploits like BitTyrant (strategically minimize uploads) and BitThief (download without uploading at all) that game the system. When we replicated the 2008 SIGCOMM paper proposing PropShare—a proportional bandwidth allocation scheme that actually implements true tit-for-tat—we found something unexpected.

Fairness maintains performance. PropShare achieves competitive download speeds while preventing exploitation. As more peers adopt it, system-wide performance improves.

This project was an attempt to replicate that paper. We were building off of PyTorrent by Alexis Gallèpe, incidentally had to make bunch of modifications to get the PyTorrent protocol up to standard with the BEP-3 spec.

Key Takeaways

For protocol designers: Small implementation details create significant incentive differences. BitTorrent's "equal share among winners" seemed minor but altered the incentive structure substantially. When designing distributed systems with competing agents, carefully model the actual incentives you're creating. Test your mechanisms against strategic or even adversarial agents, not just honest ones. Somewhat similar thinking we had to apply to the better egos project where social vehicles were quantified slightly adversarially when training an ego-vehicle according to a custom policy. But different project, check out that page to learn more.

For P2P systems: Bittorent itself a little outdated these days, but the concept of proportional allocation that we applied here is a powerful primitive. The principles here extend beyond BitTorrent to blockchain consensus, distributed storage (IPFS), CDNs, and any system where you need to prevent strategic free-riding without sacrificing efficiency. I'll probably update this website for more explicit connections to these systems later.

Replication matters!. We recreated decade-old networking research using modern infrastructure (AWS instead of PlanetLab), validated foundational results, and demonstrated that fairness mechanisms can actually improve system-wide performance—a counterintuitive finding worth building on. That being said, there were some caveats in this replication process. Not everything was kosher and there were some wrinkles that weren't ironed out; more on that below.


Introduction

BitTorrent changed file sharing by distributing the load across peers instead of relying on a central server. The conventional wisdom: it uses tit-for-tat incentives to encourage cooperation. You upload to others, they upload to you. Free-riders get punished, cooperators get rewarded.

BitTorrent P2P Architecture Figure 1: Traditional client-server architecture (left) vs. BitTorrent's peer-to-peer model (right). Instead of all clients downloading from a single server, peers share file pieces with each other, distributing the load across the network.

However, BitTorrent's actual mechanism differs from this conception.

In 2008, researchers Dave Levin, Katrina LaCurts, Neil Spring, and Bobby Bhattacharjee published a paper revealing BitTorrent's true mechanism: it's an auction, not a reciprocal exchange.

How the Auction Works

Every BitTorrent peer periodically selects 3-4 neighbors to "unchoke" and send data to. The selection criteria? Who uploaded the most to me recently.

This sounds like tit-for-tat. However, there's a critical detail: once you're selected as a top bidder, you receive equal bandwidth share regardless of how much you contributed.

Consider a bandwidth auction where:

  • You bid by uploading data
  • The top 3-4 bidders win
  • All winners split the prize equally

The rational (and somewhat messed up) strategy? Bid just enough to stay in the top tier, but not a byte more. Uploading 100 KB/s provides no advantage over 51 KB/s if both keep you in the top tier.

A Quick Note on Choking

In BitTorrent terminology, "choking" means refusing to upload to a peer, while "unchoking" means allowing uploads to that peer. In other words, each peer only ever has limited bandwidth (regrettably...) – so you can only serve a few peers at a time. When you "unchoke" someone, you're opening the floodgates and sending them data. When you "choke" them, you're closing it off. It's really like any resource-allocation problem, and this concept of choking/unchoking and when you do it is more of an implementation detail.

Every BitTorrent client maintains two types of unchoked connections:

  • Regular unchokes (3-4 peers): These are the auction winners—the peers who uploaded the most to you recently. They get consistent access to your bandwidth.
  • Optimistic unchokes (1 peer): Every 30 seconds, you randomly unchoke someone new to discover potentially better trading partners. This gives newcomers a chance to prove themselves.

Peer Choking Dynamics Figure 2: Download rate vs. unchoke frequency across different peers in our testbed. Left: Total unchokes. Middle: Regular unchokes (auction winners). Right: Optimistic unchokes (random exploration). Notice how download performance correlates strongly with regular unchokes—the auction mechanism in action.

The Exploits

This misalignment didn't go unnoticed:

BitTyrant (strategic selfishness): Calculates the minimum upload contribution needed to remain unchoked at each peer, maximizing download-to-upload ratio. It's not breaking the rules—it's playing by the actual rules instead of the assumed ones.

BitThief (pure exploitation): Downloads without uploading at all by exploiting "optimistic unchoking"—a feature where BitTorrent periodically unchokes random peers to discover new bandwidth sources. BitThief continuously hops between optimistic unchoke slots, never reciprocating.


Methods

PropShare: Actual Tit-for-Tat

The paper proposed PropShare, a deceptively simple fix: allocate bandwidth proportionally to contribution.

Anywho, we can think about the proportional-share algorithm as such: if Alice uploads 100 KB/s to me and Bob uploads 50 KB/s, Alice gets twice the bandwidth. No more equal-split-among-winners. Your reward scales directly with your contribution. This is what people thought BitTorrent was doing all along.

The Surprising Claim

In theory, all this should work because there's incentive alignment, sybil resistance, and collusion resilience as well. Contributing more always gets you more, so no strategic gaming of threshold effects. Creating multiple fake identities doesn't help—you still have to split your upload bandwidth across them. Groups of peers coordinating can't extract extra bandwidth without actually contributing it.

The paper claimed PropShare maintains competitive performance despite enforcing stricter fairness. In many cases, PropShare peers download faster than vanilla BitTorrent peers. This seems counterintuitive because stricter fairness should constrain selfish behavior, which typically reduces efficiency. Enforcing reciprocity might be expected to slow things down.

We set out to replicate these results.


Implementation

The original study used PlanetLab, a global distributed testbed that no longer exists. We needed to recreate their experimental setup using modern infrastructure.

AWS Distributed Testbed Architecture Figure 3: Experimental setup from the original Levin et al. (2008) paper. This shows the target results we aimed to reproduce—demonstrating how PropShare maintains stable performance across different swarm compositions while vanilla BitTorrent degrades.

Infrastructure: AWS Distributed Testbed

I built a 16-node testbed across multiple AWS regions using t2.micro Ubuntu instances (computational free-tier limit: 32 vCPUs).

I built a system that allowed for experiments to be configured via YAML, making it easy to test different swarm compositions. One deeply regrettable fact is that we weren't really aware that Kubernetes could handle all of this for us and connect to AWS. So I just recreated a bare-bones, automated node-requisitioning/management module that did this for us. Welp...

YAML
regions:
  - name: "us-east-1"
    seeders: 2
    leechers: 5
  - name: "eu-west-1"
    seeders: 1
    leechers: 3
  - name: "ap-southeast-1"
    seeders: 1
    leechers: 2

aws:
  instance_type: "t2.micro"
  security_group: "default"

timeout_minutes: 30

My automation code handled:

  • Automatic security group creation with all-to-all communication
  • Coordinated instance deployment and configuration
  • Automatic cleanup to prevent runaway costs
  • Heterogeneous bandwidth caps per peer (following Piatek et al.'s distribution)

Since AMI IDs differ per region and change with Ubuntu updates, I automated AMI discovery:

Python
def get_latest_ubuntu_ami(self, region):
    """Get latest Ubuntu 22.04 AMI for specified region."""
    ec2_client = boto3.client('ec2', region_name=region)

    response = ec2_client.describe_images(
        Owners=['099720109477'],  # Canonical's AWS account
        Filters=[
            {'Name': 'name', 'Values': ['ubuntu/images/hvm-ssd/ubuntu-jammy-22.04*']},
            {'Name': 'state', 'Values': ['available']},
            {'Name': 'architecture', 'Values': ['x86_64']}
        ]
    )

    # Sort by creation date, return newest
    latest_ami = sorted(response['Images'],
                       key=lambda x: x['CreationDate'], reverse=True)[0]
    return latest_ami['ImageId']

Instances were deployed in parallel across all regions using ThreadPoolExecutor:

Python
with ThreadPoolExecutor() as executor:
    futures = []

    for region in regions:  # e.g., us-east-1, eu-west-1, ap-southeast-1
        ami_id = region_ami_map[region['name']]
        futures.append(
            executor.submit(deploy_region, region, torrent_url, seed_fileurl, ami_id)
        )

    for future in futures:
        region_name, instance_ids = future.result()
        print(f"✓ Launched {len(instance_ids)} instances in {region_name}")

This approach allowed me to spin up geographically distributed testbeds in minutes rather than hours. Each experiment used 3 seeders with 128 KB/s combined upload capacity sharing 5 MB files.

Experimental Setup and Configuration Figure 4: Figure 8 from the original Levin et al. (2008) paper showing download times vs. fraction of PropShare clients. This is the key result we aimed to replicate—PropShare (circles) maintains stable performance while vanilla BitTorrent (X's) degrades as PropShare adoption increases.

Two Protocols, One Codebase

We modified an existing PyTorrent implementation to the BEP 3 BitTorrent specification. The implementation was split across two branches—one for vanilla BitTorrent, one for PropShare—allowing us to run controlled experiments comparing the two protocols.

Vanilla BitTorrent (Auction Mechanism):

Every 10 seconds, the client performs "regular unchoking":

Python
sorted_peers = sorted(peers, key=lambda p: p.calculate_download_rate(), reverse=True)
unchoked_peers = sorted_peers[:3]  # Top 3 bidders win

The top 3 peers by download rate get unchoked and receive equal bandwidth share—this is the auction. Once you're in the top tier, contributing 51 KB/s gets you the same as contributing 100 KB/s.

Every 30 seconds, one random peer gets "optimistically unchoked" to discover new high-bandwidth sources:

Python
lucky_peer = random.choice(eligible_peers)
lucky_peer.send_unchoke()

PropShare (Proportional Allocation):

The key insight: PropShare uses the same unchoking logic (top 3 peers get unchoked), but implements probabilistic packet-level allocation to achieve proportionality.

Why probabilistic? The original paper identified the bandwidth ceiling for each peer and allocated proportional fractions. However, determining accurate bandwidth ceilings in our AWS testbed was infeasible due to network variability. Instead, we used a probabilistic approach: when a peer requests a block, we send it with probability proportional to their contribution. This is stateless, requires no rate limiting or buffering, and converges to correct proportions through the law of large numbers.

Python
def confirm_send_to_peer(peer):
    total_rate = sum(p.download_rate for p in unchoked_peers)
    peer_rate = peer.download_rate
    probability = peer_rate / total_rate
    return random.uniform(0, 1) < probability

If Alice uploaded at 100 KB/s and Bob at 50 KB/s (total 150 KB/s):

  • Alice gets packets with probability 100/150 = 66.7%
  • Bob gets packets with probability 50/150 = 33.3%

The optimistic unchoke peer always gets packets (probability = 1.0) to ensure new peers can prove themselves.

Bandwidth Tracking:

We used exponential moving averages (EMA) with a 20-second window to calculate download/upload rates:

Python
def ema(series, time_window=20.0):
    weighted_sum = sum(bytes * exp(-dt / time_window) for t, bytes in series)
    return weighted_sum / total_weight

This smooths out short-term spikes and gives more weight to recent contributions, preventing peers from gaming the system by uploading briefly then freeloading.

Rarest-First Piece Selection:

To maximize swarm efficiency, we prioritized downloading the rarest pieces first:

Python
sorted_pieces = sorted(pieces, key=lambda p: len(p.peers))  # Fewest peers = rarest

This ensures rare pieces propagate quickly through the swarm, preventing bottlenecks where everyone has the same pieces.

Request Management:

We tracked outstanding requests with a 2-second timeout and capped total outstanding requests at 5 to prevent network congestion. If a peer doesn't respond within 2 seconds, we re-request the block from another peer.


Experimental Design

Each experiment ran multiple trials with different swarm compositions:

PropShare AdoptionPropShare ClientsVanilla ClientsDescription
0%04Pure vanilla BitTorrent (baseline)
25%13Minority PropShare
50%22Equal split
75%31Majority PropShare
100%40Pure PropShare

For each configuration, we measured:

  • Average download time per client type
  • Total unchokes (regular + optimistic)
  • Download rate correlation with unchoke frequency
  • Bandwidth utilization across the swarm

All experiments used 5 MB test files with 3 seeders providing 128 KB/s combined upload capacity. We ran at least 3 trials per configuration and computed 95% confidence intervals.

Challenges We Overcame:

  1. Network heterogeneity: AWS instances have different bandwidth capabilities. We implemented bandwidth caps per peer following Piatek et al.'s distribution to simulate realistic conditions.

  2. Timing precision: With a smaller testbed (16 nodes vs. PlanetLab's 110), we had to increase peer exchange frequency and optimize the tracker refresh rate to avoid artificial delays.

  3. Logging overhead: Tracking every unchoke event and download rate calculation generated significant log data. We implemented efficient CSV-based logging with exponential moving averages to minimize performance impact.

  4. Race conditions: With multiple threads handling peer connections, piece management, and unchoking decisions, we carefully synchronized state updates to prevent corrupted data.


Results

We attempted to replicate Figure 8 from the original paper, measuring average download times as the fraction of PropShare clients varies from 0% to 100%. While our results don't perfectly match the original, they support the paper's key findings.

Download Time vs PropShare Adoption - Figure 8 Replication Figure 5: Our attempt at replicating the paper's key result. PropShare clients (blue) maintain stable download times regardless of swarm composition, while vanilla BitTorrent clients (red) experience degraded performance as PropShare adoption increases. While the exact values differ from the original, the trends support the paper's counterintuitive claim: fairness doesn't hurt performance.

What We Found

PropShare maintains stable download times across all swarm compositions. Whether 0% or 100% of peers use PropShare, download times stay consistent at around 40-50 seconds.

Vanilla BitTorrent degrades as PropShare adoption increases. At 0% PropShare (pure BitTorrent swarm), vanilla clients download in ~45 seconds. As PropShare adoption grows, vanilla BitTorrent clients see their download times increase to ~70+ seconds.

System-wide performance improves with PropShare adoption. The total completion time across all peers decreases as more adopt PropShare, even though PropShare enforces stricter fairness.

Why Does This Happen?

The paper doesn't fully explain this phenomenon, which is why we focused our replication efforts here. Our hypothesis based on the experiments:

Reduced strategic gaming: When everyone plays fairly, there's less bandwidth wasted on gaming threshold effects. Peers stop oscillating around "just enough" contributions and simply exchange data efficiently.

Better bandwidth utilization: Proportional allocation creates smoother traffic patterns. No more feast-or-famine dynamics where you're either in the top tier (equal share) or completely choked (nothing).

Network effects: PropShare peers effectively subsidize the swarm. Because they allocate bandwidth fairly, they create more opportunities for piece exchange, which benefits everyone—even selfish vanilla clients trying to exploit them.

This resembles how traffic flows better when drivers cooperate rather than constantly switching lanes to gain marginal advantages.


Conclusion

Mechanism design matters more than you think. BitTorrent worked well despite its incentive flaws because most users ran honest clients. As soon as exploits emerged (BitTyrant, BitThief), the cracks showed. When designing distributed systems with competing agents, test your incentives against strategic agents, not just honest ones.

The principles here extend beyond BitTorrent to blockchain consensus (preventing strategic block withholding), distributed storage systems like IPFS (incentivizing seeding of rare content), and CDNs (preventing edge nodes from free-riding). Proportional allocation is a powerful primitive for fairness without sacrificing efficiency.

Fair systems can achieve competitive performance. When you remove incentives for strategic behavior, you remove the overhead of that behavior. This challenges the common assumption that fairness necessarily imposes performance costs.


Technical Details

Original Paper: Levin, D., LaCurts, K., Spring, N., & Bhattacharjee, B. (2008). BitTorrent is an auction: analyzing and improving BitTorrent's incentives. SIGCOMM Computer Communication Review, 38(4), 243-254.

Implementation: Custom BitTorrent client (Python) implementing both vanilla and PropShare protocols with peer-to-peer seeding, piece selection, and bandwidth tracking.

Read the full technical writeup: Reproducing Network Research Blog Post


Acknowledgments

This replication was a true team effort. Thanks to Yousef AbuHashem, Fabio Ibanez, and Jacob Roberts-Baca for debugging AWS networking issues and collaborative problem-solving throughout the project. Thanks to the CS244 teaching team for guidance on reproducing decade-old networking research and to the authors of the original paper for their foundational work.