Skip to content

GET operation fails when caching contracts with version-based update validation #2018

@sanity

Description

@sanity

Bug Description

GET operations fail when attempting to cache contracts that implement version-based state validation (like web-container-contract), if the contract is already cached locally with the same version.

Steps to Reproduce

  1. Publish a contract using web-container-contract (which implements version checking in its update_state() method)
  2. Contract gets cached locally via PUT operation
  3. Perform a GET operation for the same contract
  4. GET retrieves contract from network successfully
  5. GET attempts to cache it locally via PutQuery
  6. Fails with: invalid contract update, reason: New state version X must be higher than current version X

Root Cause

In crates/core/src/operations/get.rs:970-1046, when GET receives a contract from the network, it determines if it should cache locally:

let should_put = if is_original_requester && subscribe_requested {
    true
} else {
    op_manager.ring.should_seed(&key)
};

If caching is needed, it calls PutQuery which triggers the contract's update_state() method. For contracts like web-container-contract that enforce strict version ordering:

if metadata.version <= current_version {
    return Err(ContractError::InvalidUpdateWithInfo {
        reason: format!(
            "New state version {} must be higher than current version {}",
            metadata.version, current_version
        ),
    });
}

This rejects the update because the network version equals the local cached version.

Error Log

ERROR freenet::server::path_handlers: error getting contract: client error: 
error while executing operation in the network: update error for contract U6odK7aUsr9QXM9oQrUMuyUEyqDBzYBsFmYbLcQSwgY, 
reason: execution error: invalid contract update, reason: 
New state version 29361237 must be higher than current version 29361237

Context

This bug was exposed after PR #1996 fixed state persistence after PUT merge. Previously, the local cache might have been stale, so the version conflict didn't occur as frequently.

Note: "version" is not a Freenet protocol concept - it's implemented by individual contracts (like web-container-contract) in their state and validation logic.

Proposed Solutions

  1. GET operation check: Before attempting PutQuery, check if local cached state matches network state (skip caching if identical)
  2. Contract-side fix: Modify contracts to allow idempotent updates (equal versions accepted if state is identical)
  3. Alternative caching mechanism: GET should use a different method that doesn't trigger update_state() validation for simple caching

Version

Freenet v0.1.35

Related Issues/PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-contractsArea: Contract runtime, SDK, and executionE-mediumExperience needed to fix/implement: Medium / intermediateP-highHigh priorityT-bugType: Something is broken

    Type

    No type

    Projects

    Status

    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions