Skip to content

Commit 7a06b34

Browse files
sgbettclaude
andcommitted
fix(wallet-postgres): sync spendable boolean on state transitions
update_output_state, lock_utxos, and release_stale_pending! now set the legacy spendable boolean column alongside the state column. filter_outputs updated to use the same dual-column WHERE clause as find_spendable_outputs. Without this, outputs transitioned to :spent or :pending via the state column would still appear as spendable: true to filter_outputs and any other query using the legacy boolean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 88246ef commit 7a06b34

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

gem/bsv-wallet-postgres/lib/bsv/wallet_postgres/postgres_store.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,14 @@ def find_spendable_outputs(basket: nil, min_satoshis: nil, sort_order: :desc)
176176
def update_output_state(outpoint, new_state, pending_reference: nil, no_send: nil)
177177
state_str = new_state.to_s
178178

179+
# Keep legacy spendable boolean in sync so filter_outputs and other
180+
# queries that haven't migrated to the state column still work.
181+
spendable_bool = new_state == :spendable
182+
179183
if new_state == :pending
180184
updates = {
181185
state: state_str,
186+
spendable: spendable_bool,
182187
pending_since: Sequel.lit('NOW()'),
183188
pending_reference: pending_reference,
184189
no_send: no_send ? true : false,
@@ -190,6 +195,7 @@ def update_output_state(outpoint, new_state, pending_reference: nil, no_send: ni
190195
else
191196
updates = {
192197
state: state_str,
198+
spendable: spendable_bool,
193199
pending_since: nil,
194200
pending_reference: nil,
195201
no_send: false
@@ -232,6 +238,7 @@ def lock_utxos(outpoints, reference:, no_send: false)
232238
.returning(:outpoint)
233239
.update(
234240
state: 'pending',
241+
spendable: false,
235242
pending_since: Sequel.lit('NOW()'),
236243
pending_reference: reference,
237244
no_send: no_send ? true : false,
@@ -264,6 +271,7 @@ def release_stale_pending!(timeout: 300)
264271
.returning(:outpoint)
265272
.update(
266273
state: 'spendable',
274+
spendable: true,
267275
pending_since: nil,
268276
pending_reference: nil,
269277
no_send: false,
@@ -386,7 +394,7 @@ def filter_outputs(ds, query)
386394
ds = ds.where(outpoint: query[:outpoint]) if query[:outpoint]
387395
ds = ds.where(basket: query[:basket]) if query[:basket]
388396
ds = apply_array_filter(ds, :tags, query[:tags], query[:tag_query_mode])
389-
ds = ds.where(spendable: true) unless query[:include_spent]
397+
ds = ds.where(Sequel.lit('(state = ? OR (state IS NULL AND spendable = TRUE))', 'spendable')) unless query[:include_spent]
390398
ds
391399
end
392400

0 commit comments

Comments
 (0)