Webhook and ingest were writing Trust/client numbers (often sats or lifetime received) into wallet_addresses.btc, so alerts showed fake balances like 48 BTC. Use mempool funded-spent like Tron.
Co-authored-by: Cursor <cursoragent@cursor.com>
Two bugs found during device 6A906030 upload replay analysis:
1. create_log() used file_put_contents(FILE_APPEND) without LOCK_EX.
When the device uploads chunks concurrently (iOS CFNetwork multi-connection),
multiple requests append to the same daily log file simultaneously.
Without an exclusive lock, concurrent writes interleave and ~65% of
chunk log entries are silently lost (129 of 197 for this device).
Fix: add LOCK_EX to prevent interleaving.
2. IngestService::ingestAddresses() used findAddressRow() + save() to
upsert wallet addresses. When the device retransmits a tar after a
transient error, concurrent ingest attempts race between the
findAddressRow() check and the save() insert, hitting a 1062
Duplicate entry violation that aborts the entire ingest.
Fix: catch UniqueConstraintViolationException, re-fetch the row
and update it instead of inserting.
Co-authored-by: Cursor <cursoragent@cursor.com>