Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
eaa74b8
add draft for clients
Jiloc Mar 11, 2025
c2ad64b
add deposit cron management
Jiloc Mar 11, 2025
bf89133
add missing deposit file
Jiloc Mar 12, 2025
e85e83d
move cron to a different app
Jiloc Mar 12, 2025
f54e53b
add emily-cron to docker compose. log the cron output
Jiloc Mar 12, 2025
7a16ed8
add logs
Jiloc Mar 12, 2025
c38b72f
fix emily client. remove rbf and pending management
Jiloc Mar 12, 2025
de0a710
add rbf management
Jiloc Mar 12, 2025
12271d5
add management for long pending deposits
Jiloc Mar 12, 2025
a89392c
add deployer_address setting
Jiloc Mar 12, 2025
0eb2d2f
add unit tests
Jiloc Mar 12, 2025
33b8931
Merge branch 'feat/sidecar-manage-locktime' into feat/sidecar-manage-rbf
Jiloc Mar 12, 2025
515a43e
add unit tests and fixes
Jiloc Mar 12, 2025
4fc5431
Merge branch 'feat/sidecar-manage-rbf' into feat/sidecar-manage-long-…
Jiloc Mar 12, 2025
5ae0270
add unit tests
Jiloc Mar 12, 2025
7fc57b1
Merge branch 'main' into feat/sidecar-manage-long-pending-deposits
Jiloc May 8, 2025
a6f4e61
change pending confirmed rbf log to info
Jiloc May 8, 2025
5ba7806
black format
Jiloc May 8, 2025
c076ac0
remove merge refuses
Jiloc May 8, 2025
e51e393
remove merge leftovers
Jiloc May 12, 2025
c4116cc
improve long_pending_txs readability
Jiloc May 12, 2025
b1d8ae7
deposit_time -> deposit_last_update
Jiloc May 12, 2025
052f3d4
fix test
Jiloc May 12, 2025
4da406d
do not bail if hiro api fails
Jiloc May 12, 2025
edf9234
black format
Jiloc May 12, 2025
d41db61
Merge branch 'main' into feat/sidecar-manage-long-pending-deposits
Jiloc May 12, 2025
c02aff6
explicitly ask for UTC datetime
Jiloc May 20, 2025
61500db
add status check
Jiloc May 20, 2025
1d01c00
deposit_last_update is now a function
Jiloc May 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions emily_cron/app/models/deposit.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from dataclasses import asdict, dataclass, field
from enum import Enum
import functools
from typing import Any, Optional, Self

from bitcoinlib.scripts import Script
Expand Down Expand Up @@ -63,10 +62,9 @@ def max_fee(self) -> int:
max_fee_bytes = bytes.fromhex(script.view(as_list=True)[0])
return int.from_bytes(max_fee_bytes[:8], byteorder="big", signed=False)

@functools.cached_property
def deposit_time(self) -> int:
def deposit_last_update(self) -> int:
"""Get the timestamp from the last update block hash."""
from ..clients import HiroAPI # Moved import here to avoid circular import
from ..clients import HiroAPI # avoid circular import

return HiroAPI.get_stacks_block(self.last_update_block_hash).time

Expand Down
58 changes: 57 additions & 1 deletion emily_cron/app/services/deposit_processor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import logging
from datetime import datetime, UTC
from itertools import chain, groupby
from json import JSONDecodeError
from typing import Iterable

from requests.exceptions import RequestException, JSONDecodeError

from ..clients import PrivateEmilyAPI, MempoolAPI
from ..models import (
DepositUpdate,
Expand Down Expand Up @@ -69,7 +73,7 @@ def process_rbf_transactions(
bitcoin_chaintip_height
< tx.confirmed_height + settings.MIN_BLOCK_CONFIRMATIONS
):
logger.warning(
logger.info(
f"Confirmed transaction {tx.bitcoin_txid} is not yet eligible for RBF replacement"
)
else:
Expand Down Expand Up @@ -203,6 +207,55 @@ def process_expired_locktime(

return updates

def process_long_pending(
self,
enriched_deposits: list[EnrichedDepositInfo],
) -> list[DepositUpdate]:
"""Process long-pending transactions.

Args:
enriched_deposits: List of enriched deposit information

Returns:
list[DepositUpdate]: List of deposit updates
"""
updates = []

current_time = int(datetime.now(UTC).timestamp())

long_pending_txs = []
for tx in enriched_deposits:
# Only check pending transactions
if tx.status != RequestStatus.PENDING.value:
continue
# that we can't find via the mempool API (it might have been dropped)
if tx.in_mempool:
continue
Comment thread
djordon marked this conversation as resolved.

try:
# and have been pending for too long
if current_time - tx.deposit_last_update() > settings.MAX_UNCONFIRMED_TIME:
long_pending_txs.append(tx)
except (RequestException, ValueError, JSONDecodeError) as e:
logger.warning(
f"Could not check pending status for deposit {tx.bitcoin_txid} due to "
f"API error fetching block {tx.last_update_block_hash}: {e}. Skipping."
)

for tx in long_pending_txs:
logger.info(f"Marking long-pending transaction {tx.bitcoin_txid} as FAILED")
updates.append(
DepositUpdate(
bitcoin_txid=tx.bitcoin_txid,
bitcoin_tx_output_index=tx.bitcoin_tx_output_index,
status=RequestStatus.FAILED.value,
status_message=f"Pending for too long ({settings.MAX_UNCONFIRMED_TIME} seconds)",
)
)

logger.info(f"Found {len(long_pending_txs)} long-pending transactions to mark as FAILED")
return updates

def update_deposits(self) -> None:
"""Update deposit statuses.

Expand Down Expand Up @@ -237,6 +290,9 @@ def update_deposits(self) -> None:
rbf_updates = self.process_rbf_transactions(enriched_deposits, bitcoin_chaintip_height)
updates.extend(rbf_updates)

# Process long-pending transactions
pending_updates = self.process_long_pending(enriched_deposits)
updates.extend(pending_updates)
# Apply updates
if updates:
logger.info(f"Updating {len(updates)} deposit statuses")
Expand Down
3 changes: 3 additions & 0 deletions emily_cron/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@

# The number of confirmations required for a deposit update to be considered final
MIN_BLOCK_CONFIRMATIONS = int(os.getenv("MIN_BLOCK_CONFIRMATIONS", 6))

# Maximum time (in seconds) a transaction can remain unconfirmed before being marked as FAILED
MAX_UNCONFIRMED_TIME = int(os.getenv("MAX_UNCONFIRMED_TIME", 60 * 60 * 24)) # 24 hours in seconds
1 change: 1 addition & 0 deletions emily_cron/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
logger.info(f"MEMPOOL_API_URL: {settings.MEMPOOL_API_URL}")
logger.info(f"HIRO_API_URL: {settings.HIRO_API_URL}")
logger.info(f"MIN_BLOCK_CONFIRMATIONS: {settings.MIN_BLOCK_CONFIRMATIONS}")
logger.info(f"MAX_UNCONFIRMED_TIME: {settings.MAX_UNCONFIRMED_TIME}")
logger.info("=" * 80)


Expand Down
Loading
Loading