wallets 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/wallets/models/hold.rb +16 -0
- data/lib/wallets/models/wallet.rb +26 -6
- data/lib/wallets/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d628d500b3ad1dfb236b6181fe30f976ae450aa9d4b8d8f5eb609969c6d59e66
|
|
4
|
+
data.tar.gz: 7c91562327a82f56429055df8f5b40e5644a226b7a83bfde9ed3cb68628faec0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8dd70a121851414b83efe8b1db52fff694a9c5b8a624135413d19c0e47d2a641538464d23879f3bbece40dacb87983cbe8af9f6ff6ed54d129127ef256de81c4
|
|
7
|
+
data.tar.gz: 903e0a69db10cf20c2502ff86a5914ffcbad2713cee1ae6e6f8591c53b52bae9fdfc61f61defe79130be9b5f9a496f849a6f6cbbaea2e5977e34a6e34751b82f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [0.4.2] - 2026-10-18
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- **A rolled-back command no longer poisons the wallet or hold instance it wrote.** Every command starts by locking its row, and Rails refuses to lock a record with unsaved changes. When a command's savepoint or the caller's transaction was rolled back after the command had written the row (a block that spends inside a command and is then refused, a `transaction { wallet.debit(...); raise }` the caller rescues), Rails kept the cached `balance`, `ledger_revision` and `updated_at` the command had written in memory as unsaved changes, and the next command on the same wallet instance raised `RuntimeError: Locking a record with unpersisted changes is not supported` instead of running; a rolled-back release or capture did the same to its hold. The columns a command writes are the ledger's, not the caller's, and the lock reads the row again anyway, so `lock!` discards them first. A change the caller made to any other attribute is still refused, as Rails intends. Found by installing usage_credits 1.0.0 into a fresh app; its `spend_credits_on` is the first shape.
|
|
6
|
+
|
|
1
7
|
## [0.4.1] - 2026-10-18
|
|
2
8
|
|
|
3
9
|
### Documentation
|
data/lib/wallets/models/hold.rb
CHANGED
|
@@ -124,6 +124,22 @@ module Wallets
|
|
|
124
124
|
# nothing. Why it ended is recorded next to why it began, never over it.
|
|
125
125
|
#
|
|
126
126
|
# hold.release!(reason: "cleared_by_operator", metadata: {actor_id: operator.id})
|
|
127
|
+
# The columns a release or a capture writes on the hold row; the caller
|
|
128
|
+
# never sets them after the hold is placed.
|
|
129
|
+
COMMAND_WRITTEN_COLUMNS = %w[released_at release_reason release_metadata capture_transaction_id updated_at].freeze
|
|
130
|
+
private_constant :COMMAND_WRITTEN_COLUMNS
|
|
131
|
+
|
|
132
|
+
# A release or a capture locks the hold row, and Rails refuses to lock a
|
|
133
|
+
# record with unsaved changes: a rolled-back release or capture leaves
|
|
134
|
+
# what it wrote in memory as unsaved changes, so retrying it on the same
|
|
135
|
+
# instance would raise. Those columns are the command's, and the lock
|
|
136
|
+
# reads the row again, so they are discarded first (see
|
|
137
|
+
# `Wallets::WalletBase#lock!`).
|
|
138
|
+
def lock!(lock = true)
|
|
139
|
+
restore_attributes(changed & COMMAND_WRITTEN_COLUMNS) if persisted?
|
|
140
|
+
super
|
|
141
|
+
end
|
|
142
|
+
|
|
127
143
|
def release!(reason: nil, metadata: {})
|
|
128
144
|
raise InvalidHold, "Only a saved hold can be released" unless persisted?
|
|
129
145
|
|
|
@@ -66,6 +66,25 @@ module Wallets
|
|
|
66
66
|
ARRIVAL_HOLD_OPTIONS = %i[category until metadata].freeze
|
|
67
67
|
private_constant :ARRIVAL_HOLD_OPTIONS
|
|
68
68
|
|
|
69
|
+
# The columns the ledger itself writes on the wallet row
|
|
70
|
+
# (`refresh_cached_balance!`); the caller never sets them.
|
|
71
|
+
LEDGER_WRITTEN_COLUMNS = %w[balance ledger_revision updated_at].freeze
|
|
72
|
+
private_constant :LEDGER_WRITTEN_COLUMNS
|
|
73
|
+
|
|
74
|
+
# Every command starts by locking the wallet row, and Rails refuses to
|
|
75
|
+
# lock a record with unsaved changes. A rolled-back command leaves
|
|
76
|
+
# exactly that behind: the cached balance, the revision and `updated_at`
|
|
77
|
+
# it had written stay in memory, marked as unsaved changes, once its
|
|
78
|
+
# savepoint or the caller's transaction is rolled back, and the next
|
|
79
|
+
# command on the same instance would raise. Those columns are the
|
|
80
|
+
# ledger's, not the caller's, and the lock reads the row again anyway,
|
|
81
|
+
# so they are discarded first. A change to any other attribute is the
|
|
82
|
+
# caller's, and Rails' refusal stands.
|
|
83
|
+
def lock!(lock = true)
|
|
84
|
+
restore_attributes(changed & LEDGER_WRITTEN_COLUMNS) if persisted?
|
|
85
|
+
super
|
|
86
|
+
end
|
|
87
|
+
|
|
69
88
|
self.table_suffix = "wallets"
|
|
70
89
|
|
|
71
90
|
# =========================================
|
|
@@ -1642,12 +1661,13 @@ module Wallets
|
|
|
1642
1661
|
# the balance did not move, because `touch` writes nothing under
|
|
1643
1662
|
# `no_touching`.
|
|
1644
1663
|
#
|
|
1645
|
-
# `update!` rather than assigning and then saving
|
|
1646
|
-
#
|
|
1647
|
-
#
|
|
1648
|
-
#
|
|
1649
|
-
#
|
|
1650
|
-
#
|
|
1664
|
+
# `update!` rather than assigning and then saving, so nothing sits pending
|
|
1665
|
+
# between commands. A rollback can still leave these columns pending:
|
|
1666
|
+
# once the real transaction, or a savepoint the caller opened, rolls
|
|
1667
|
+
# back, Active Record restores the values this write left in memory as
|
|
1668
|
+
# unsaved changes. `lock!` discards exactly those (LEDGER_WRITTEN_COLUMNS)
|
|
1669
|
+
# before locking, so the next command can lock the wallet and reads the
|
|
1670
|
+
# row again.
|
|
1651
1671
|
def refresh_cached_balance!
|
|
1652
1672
|
available = current_balance
|
|
1653
1673
|
|
data/lib/wallets/version.rb
CHANGED