Skip to content

GET request fails to find locally cached contract after different client's PUT #2214

@sanity

Description

@sanity

Problem Summary

When Client 1 (Alice) PUTs a contract and then Client 2 (Bob) tries to GET the same contract from the same node, the GET times out instead of finding the contract in local storage.

How to Reproduce

Prerequisites

  • A Freenet node running and connected to the network (e.g., technic connected to gateway)
  • riverctl CLI installed

Steps

# Set up test directories
ALICE_DIR=/tmp/alice-cli-test
BOB_DIR=/tmp/bob-cli-test
mkdir -p $ALICE_DIR $BOB_DIR

# Step 1: Alice creates a room (this does a PUT)
riverctl --config-dir $ALICE_DIR room create --name 'test-room' --nickname 'alice' -f json
# Note the owner_key from output

# Step 2: Alice creates an invite
riverctl --config-dir $ALICE_DIR invite create <OWNER_KEY> -f json
# Note the invitation_code from output

# Step 3: Bob accepts invite (this does a GET - THIS TIMES OUT)
riverctl --config-dir $BOB_DIR invite accept "<INVITATION_CODE>" --nickname bob -f json
# Error: Timeout waiting for GET response after 10 seconds

Alternative reproduction (direct WebSocket API)

The test file crates/core/tests/multi_client_get_regression.rs contains two tests:

  • test_different_client_get_after_put - Client 1 PUTs, disconnects, Client 2 GETs
  • test_concurrent_clients_put_then_get - Both clients connected, Client 1 PUTs, Client 2 GETs immediately

Note: These tests pass in the test network but the bug reproduces on live technic node.

Live Evidence (from technic logs)

02:44:06.301 - PUT operation logs "caching locally" for contract vHpRZZFdgwPKpU82wRw8FMS3iESxbZyVuEWirRL2Awu
02:44:06.529 - GET operation logs "Contract not found" for the SAME contract (228ms later)

The contract was stored during PUT but GET's local cache check returns None.

Code Path Analysis

PUT path (crates/core/src/operations/put.rs):

  • request_put() at lines 1358-1374 calls put_contract() to store locally BEFORE forwarding
  • Line 1597 logs "No peers available for forwarding - caching locally" (gateway in skip_list)

GET path (crates/core/src/client_events/mod.rs):

  • Lines 853-878: GET first checks local storage via notify_contract_handler(GetQuery)
  • Lines 880-932: Returns immediately if found locally
  • Lines 934+: Routes to network if NOT found locally

What We've Ruled Out

  • ContractKey mismatch: Instance IDs are identical between PUT and GET
  • Test framework issues: Local tests pass (GET completes in ~2ms from local cache)
  • Timing: 228ms between PUT completion and GET is plenty of time

Remaining Hypotheses

  1. Storage layer issue: put_contract() succeeds but data isn't persisted correctly to redb
  2. Different storage paths: PUT and GET use different contract handlers or storage backends
  3. Client isolation: Some per-client caching that doesn't share between clients
  4. Race condition: Something specific to the live environment vs test network

Next Steps

  • Run with RUST_LOG=debug to trace exact storage flow through put_contract() and notify_contract_handler(GetQuery)
  • Verify redb database actually contains the contract after PUT
  • Compare storage lookup code paths between PUT's storage and GET's retrieval

Environment

  • Technic node at 136.62.52.28:43227 behind NAT
  • Gateway at 5.9.111.215:31337
  • Freenet version 0.1.42

Related Files

  • crates/core/tests/multi_client_get_regression.rs - Regression tests
  • crates/core/src/operations/put.rs - PUT operation
  • crates/core/src/operations/get.rs - GET operation
  • crates/core/src/client_events/mod.rs - Client request routing

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-contractsArea: Contract runtime, SDK, and executionA-networkingArea: Networking, ring protocol, peer discoveryP-highHigh priorityT-bugType: Something is broken

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions