Class: X402::BSV::ChallengeStore::Memory

Inherits:
Object
  • Object
show all
Defined in:
lib/x402/bsv/challenge_store.rb

Overview

In-memory backend suitable for development and single-process deployments. Thread-safe via Monitor. Entries expire after +ttl+ seconds and the store rejects new challenges once +max_issued+ unconsumed entries are held.

NOTE: This store is per-process. It provides no replay protection across OS processes (e.g. Puma pre-fork, multiple dynos). Production multi-process deployments should use a shared backend.

Constant Summary collapse

DEFAULT_TTL =
600
DEFAULT_MAX_ISSUED =
10_000

Instance Method Summary collapse

Constructor Details

#initialize(ttl: DEFAULT_TTL, max_issued: DEFAULT_MAX_ISSUED) ⇒ Memory

Returns a new instance of Memory.

Parameters:

  • ttl (Integer) (defaults to: DEFAULT_TTL)

    seconds before an issued challenge expires

  • max_issued (Integer) (defaults to: DEFAULT_MAX_ISSUED)

    cap on unconsumed entries



46
47
48
49
50
51
# File 'lib/x402/bsv/challenge_store.rb', line 46

def initialize(ttl: DEFAULT_TTL, max_issued: DEFAULT_MAX_ISSUED)
  @entries = {}
  @monitor = Monitor.new
  @ttl = ttl
  @max_issued = max_issued
end

Instance Method Details

#consume!(hash) ⇒ Boolean

Atomically remove an entry. Returns true if it was present and active, false otherwise. Safe to call from the settlement path without a prior lookup.

Parameters:

  • hash (String)

Returns:

  • (Boolean)


87
88
89
90
91
92
# File 'lib/x402/bsv/challenge_store.rb', line 87

def consume!(hash)
  @monitor.synchronize do
    entry = @entries.delete(hash)
    entry && !expired?(entry) ? true : false
  end
end

#lookup(hash) ⇒ X402::Challenge?

Non-binding read: returns the cached challenge or nil.

Parameters:

  • hash (String)

Returns:



72
73
74
75
76
77
78
79
# File 'lib/x402/bsv/challenge_store.rb', line 72

def lookup(hash)
  @monitor.synchronize do
    entry = @entries[hash]
    return nil unless entry && !expired?(entry)

    entry[:challenge]
  end
end

#store!(hash, challenge) ⇒ void

This method returns an undefined value.

Record an issued challenge.

Parameters:

  • hash (String)

    hex-encoded canonical sha256 of the challenge

  • challenge (X402::Challenge)

Raises:



59
60
61
62
63
64
65
66
# File 'lib/x402/bsv/challenge_store.rb', line 59

def store!(hash, challenge)
  @monitor.synchronize do
    purge_expired!
    raise StoreFullError, "challenge store at capacity (#{@max_issued})" if @entries.size >= @max_issued

    @entries[hash] = { challenge: challenge, issued_at: monotonic_now }
  end
end