Class: BSV::Wallet::LocalPool
- Inherits:
-
Object
- Object
- BSV::Wallet::LocalPool
- Includes:
- Interface::UTXOPool
- Defined in:
- lib/bsv/wallet/utxo_pool/local_pool.rb
Overview
In-process UTXO pool backed by the wallet’s own Store.
LocalPool maintains a named basket of pre-funded outputs that callers can acquire for use as inputs in transactions. Acquired outputs are locked via lock_utxos with no_send: true, making them exempt from release_stale_pending! sweeps (bug #1 fix). Releasing an output returns it to :spendable state.
When the available count drops to or below the low-water mark, acquire signals the optional replenishment worker to top up the pool. The signal uses = (not <) so the worker is triggered exactly at the boundary (bug #3 fix).
Thread safety
All public methods are safe to call concurrently. acquire holds the storage-level mutex via lock_utxos, which performs an atomic find-and-lock. The pool-level @mutex guards @state and @replenisher.
Pool basket naming
The basket name is derived as "pool:#{name}", placing all pool outputs in the structured pool: zone.
State values
status[:state] is one of:
:healthy — pool has outputs above the low-water mark
:replenishing — pool is below low-water mark and worker is running
:depleted — pool is empty and worker cannot replenish
:shutdown — pool has been shut down
Constant Summary
Constants included from Interface::UTXOPool
Interface::UTXOPool::MAX_RETRIES
Instance Attribute Summary collapse
-
#basket ⇒ Object
readonly
Returns the value of attribute basket.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#replenisher ⇒ Object
writeonly
Sets the attribute replenisher.
-
#storage ⇒ Object
readonly
Returns the value of attribute storage.
-
#target_count ⇒ Object
readonly
Returns the value of attribute target_count.
-
#target_satoshis ⇒ Object
readonly
Returns the value of attribute target_satoshis.
Instance Method Summary collapse
-
#acquire ⇒ String
Acquires an available output from the pool and locks it.
-
#initialize(name:, storage:, wallet_client:, target_count:, target_satoshis:, low_water_mark:) ⇒ LocalPool
constructor
A new instance of LocalPool.
-
#release(outpoint) ⇒ void
Releases a previously acquired output back to
:spendablestate. -
#shutdown ⇒ void
Shuts down the pool.
-
#status ⇒ Hash
Returns a summary of the pool’s current state.
Constructor Details
#initialize(name:, storage:, wallet_client:, target_count:, target_satoshis:, low_water_mark:) ⇒ LocalPool
Returns a new instance of LocalPool.
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 51 def initialize(name:, storage:, wallet_client:, target_count:, target_satoshis:, low_water_mark:) @name = name @basket = "pool:#{name}" @storage = storage @wallet_client = wallet_client @target_count = target_count @target_satoshis = target_satoshis @low_water_mark = low_water_mark @replenisher = nil @state = :healthy @mutex = Mutex.new end |
Instance Attribute Details
#basket ⇒ Object (readonly)
Returns the value of attribute basket.
42 43 44 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 42 def basket @basket end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
42 43 44 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 42 def name @name end |
#replenisher=(value) ⇒ Object (writeonly)
Sets the attribute replenisher
43 44 45 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 43 def replenisher=(value) @replenisher = value end |
#storage ⇒ Object (readonly)
Returns the value of attribute storage.
42 43 44 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 42 def storage @storage end |
#target_count ⇒ Object (readonly)
Returns the value of attribute target_count.
42 43 44 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 42 def target_count @target_count end |
#target_satoshis ⇒ Object (readonly)
Returns the value of attribute target_satoshis.
42 43 44 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 42 def target_satoshis @target_satoshis end |
Instance Method Details
#acquire ⇒ String
Acquires an available output from the pool and locks it.
Finds spendable outputs in the pool basket, then atomically locks the first candidate via lock_utxos with no_send: true. On contention (another thread claimed the output first), retries up to UTXOPool::MAX_RETRIES times before raising PoolDepletedError.
After a successful acquisition, signals the replenisher if the available count has dropped to or below the low-water mark.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 76 def acquire @mutex.synchronize { raise PoolDepletedError, @name if @state == :shutdown } MAX_RETRIES.times do candidates = @storage.find_spendable_outputs(basket: @basket) raise PoolDepletedError, @name if candidates.empty? outpoint = candidates.first[:outpoint] reference = "pool-acquire-#{SecureRandom.hex(8)}" locked = @storage.lock_utxos([outpoint], reference: reference, no_send: true) next if locked.empty? maybe_signal_replenisher(candidates.size - 1) return outpoint end raise PoolDepletedError, @name end |
#release(outpoint) ⇒ void
This method returns an undefined value.
Releases a previously acquired output back to :spendable state.
101 102 103 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 101 def release(outpoint) @storage.update_output_state(outpoint, :spendable) end |
#shutdown ⇒ void
This method returns an undefined value.
Shuts down the pool.
Stops the replenishment worker if one is running and marks the pool as :shutdown. Idempotent — safe to call more than once.
125 126 127 128 129 130 131 132 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 125 def shutdown @mutex.synchronize do return if @state == :shutdown @replenisher&.stop @state = :shutdown end end |
#status ⇒ Hash
Returns a summary of the pool’s current state.
109 110 111 112 113 114 115 116 117 |
# File 'lib/bsv/wallet/utxo_pool/local_pool.rb', line 109 def status spendable = @storage.find_spendable_outputs(basket: @basket) { available: spendable.size, target: @target_count, satoshis_committed: spendable.sum { |o| o[:satoshis].to_i }, state: current_state(spendable.size) } end |