brawny 0.1.13__py3-none-any.whl → 0.1.22__py3-none-any.whl
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.
- brawny/__init__.py +2 -0
- brawny/_context.py +5 -5
- brawny/_rpc/__init__.py +36 -12
- brawny/_rpc/broadcast.py +14 -13
- brawny/_rpc/caller.py +243 -0
- brawny/_rpc/client.py +539 -0
- brawny/_rpc/clients.py +11 -11
- brawny/_rpc/context.py +23 -0
- brawny/_rpc/errors.py +465 -31
- brawny/_rpc/gas.py +7 -6
- brawny/_rpc/pool.py +18 -0
- brawny/_rpc/retry.py +266 -0
- brawny/_rpc/retry_policy.py +81 -0
- brawny/accounts.py +28 -9
- brawny/alerts/__init__.py +15 -18
- brawny/alerts/abi_resolver.py +212 -36
- brawny/alerts/base.py +2 -2
- brawny/alerts/contracts.py +77 -10
- brawny/alerts/errors.py +30 -3
- brawny/alerts/events.py +38 -5
- brawny/alerts/health.py +19 -13
- brawny/alerts/send.py +513 -55
- brawny/api.py +39 -11
- brawny/assets/AGENTS.md +325 -0
- brawny/async_runtime.py +48 -0
- brawny/chain.py +3 -3
- brawny/cli/commands/__init__.py +2 -0
- brawny/cli/commands/console.py +69 -19
- brawny/cli/commands/contract.py +2 -2
- brawny/cli/commands/controls.py +121 -0
- brawny/cli/commands/health.py +2 -2
- brawny/cli/commands/job_dev.py +6 -5
- brawny/cli/commands/jobs.py +99 -2
- brawny/cli/commands/maintenance.py +13 -29
- brawny/cli/commands/migrate.py +1 -0
- brawny/cli/commands/run.py +10 -3
- brawny/cli/commands/script.py +8 -3
- brawny/cli/commands/signer.py +143 -26
- brawny/cli/helpers.py +0 -3
- brawny/cli_templates.py +25 -349
- brawny/config/__init__.py +4 -1
- brawny/config/models.py +43 -57
- brawny/config/parser.py +268 -57
- brawny/config/validation.py +52 -15
- brawny/daemon/context.py +4 -2
- brawny/daemon/core.py +185 -63
- brawny/daemon/loops.py +166 -98
- brawny/daemon/supervisor.py +261 -0
- brawny/db/__init__.py +14 -26
- brawny/db/base.py +248 -151
- brawny/db/global_cache.py +11 -1
- brawny/db/migrate.py +175 -28
- brawny/db/migrations/001_init.sql +4 -3
- brawny/db/migrations/010_add_nonce_gap_index.sql +1 -1
- brawny/db/migrations/011_add_job_logs.sql +1 -2
- brawny/db/migrations/012_add_claimed_by.sql +2 -2
- brawny/db/migrations/013_attempt_unique.sql +10 -0
- brawny/db/migrations/014_add_lease_expires_at.sql +5 -0
- brawny/db/migrations/015_add_signer_alias.sql +14 -0
- brawny/db/migrations/016_runtime_controls_and_quarantine.sql +32 -0
- brawny/db/migrations/017_add_job_drain.sql +6 -0
- brawny/db/migrations/018_add_nonce_reset_audit.sql +20 -0
- brawny/db/migrations/019_add_job_cooldowns.sql +8 -0
- brawny/db/migrations/020_attempt_unique_initial.sql +7 -0
- brawny/db/ops/__init__.py +3 -25
- brawny/db/ops/logs.py +1 -2
- brawny/db/queries.py +47 -91
- brawny/db/serialized.py +65 -0
- brawny/db/sqlite/__init__.py +1001 -0
- brawny/db/sqlite/connection.py +231 -0
- brawny/db/sqlite/execute.py +116 -0
- brawny/db/sqlite/mappers.py +190 -0
- brawny/db/sqlite/repos/attempts.py +372 -0
- brawny/db/sqlite/repos/block_state.py +102 -0
- brawny/db/sqlite/repos/cache.py +104 -0
- brawny/db/sqlite/repos/intents.py +1021 -0
- brawny/db/sqlite/repos/jobs.py +200 -0
- brawny/db/sqlite/repos/maintenance.py +182 -0
- brawny/db/sqlite/repos/signers_nonces.py +566 -0
- brawny/db/sqlite/tx.py +119 -0
- brawny/http.py +194 -0
- brawny/invariants.py +11 -24
- brawny/jobs/base.py +8 -0
- brawny/jobs/job_validation.py +2 -1
- brawny/keystore.py +83 -7
- brawny/lifecycle.py +64 -12
- brawny/logging.py +0 -2
- brawny/metrics.py +84 -12
- brawny/model/contexts.py +111 -9
- brawny/model/enums.py +1 -0
- brawny/model/errors.py +18 -0
- brawny/model/types.py +47 -131
- brawny/network_guard.py +133 -0
- brawny/networks/__init__.py +5 -5
- brawny/networks/config.py +1 -7
- brawny/networks/manager.py +14 -11
- brawny/runtime_controls.py +74 -0
- brawny/scheduler/poller.py +11 -7
- brawny/scheduler/reorg.py +95 -39
- brawny/scheduler/runner.py +442 -168
- brawny/scheduler/shutdown.py +3 -3
- brawny/script_tx.py +3 -3
- brawny/telegram.py +53 -7
- brawny/testing.py +1 -0
- brawny/timeout.py +38 -0
- brawny/tx/executor.py +922 -308
- brawny/tx/intent.py +54 -16
- brawny/tx/monitor.py +31 -12
- brawny/tx/nonce.py +212 -90
- brawny/tx/replacement.py +69 -18
- brawny/tx/retry_policy.py +24 -0
- brawny/tx/stages/types.py +75 -0
- brawny/types.py +18 -0
- brawny/utils.py +41 -0
- {brawny-0.1.13.dist-info → brawny-0.1.22.dist-info}/METADATA +3 -3
- brawny-0.1.22.dist-info/RECORD +163 -0
- brawny/_rpc/manager.py +0 -982
- brawny/_rpc/selector.py +0 -156
- brawny/db/base_new.py +0 -165
- brawny/db/mappers.py +0 -182
- brawny/db/migrations/008_add_transactions.sql +0 -72
- brawny/db/ops/attempts.py +0 -108
- brawny/db/ops/blocks.py +0 -83
- brawny/db/ops/cache.py +0 -93
- brawny/db/ops/intents.py +0 -296
- brawny/db/ops/jobs.py +0 -110
- brawny/db/ops/nonces.py +0 -322
- brawny/db/postgres.py +0 -2535
- brawny/db/postgres_new.py +0 -196
- brawny/db/sqlite.py +0 -2733
- brawny/db/sqlite_new.py +0 -191
- brawny-0.1.13.dist-info/RECORD +0 -141
- {brawny-0.1.13.dist-info → brawny-0.1.22.dist-info}/WHEEL +0 -0
- {brawny-0.1.13.dist-info → brawny-0.1.22.dist-info}/entry_points.txt +0 -0
- {brawny-0.1.13.dist-info → brawny-0.1.22.dist-info}/top_level.txt +0 -0
brawny/db/postgres_new.py
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
"""PostgreSQL database implementation.
|
|
2
|
-
|
|
3
|
-
Slim execution layer with 4 primitives. All business operations live in db/ops/.
|
|
4
|
-
Uses connection pooling with psycopg3.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import re
|
|
10
|
-
import threading
|
|
11
|
-
from contextlib import contextmanager
|
|
12
|
-
from typing import Any, Iterator, Literal
|
|
13
|
-
|
|
14
|
-
import psycopg
|
|
15
|
-
from psycopg.rows import dict_row
|
|
16
|
-
from psycopg_pool import ConnectionPool
|
|
17
|
-
|
|
18
|
-
from brawny.db.base_new import Database, Dialect, IsolationLevel
|
|
19
|
-
from brawny.model.errors import DatabaseError
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _rewrite(query: str) -> str:
|
|
23
|
-
"""Rewrite :name placeholders to %(name)s for psycopg."""
|
|
24
|
-
# Match :word but not ::type_cast
|
|
25
|
-
return re.sub(r"(?<!:):(\w+)", r"%(\1)s", query)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class PostgresDatabase(Database):
|
|
29
|
-
"""PostgreSQL implementation with connection pooling.
|
|
30
|
-
|
|
31
|
-
Uses psycopg3 with a synchronous connection pool.
|
|
32
|
-
Queries use :name placeholders (rewritten to %(name)s).
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
def __init__(
|
|
36
|
-
self,
|
|
37
|
-
database_url: str,
|
|
38
|
-
pool_size: int = 5,
|
|
39
|
-
pool_max_overflow: int = 10,
|
|
40
|
-
pool_timeout: float = 30.0,
|
|
41
|
-
) -> None:
|
|
42
|
-
"""Initialize PostgreSQL database.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
database_url: PostgreSQL connection URL
|
|
46
|
-
pool_size: Minimum pool connections
|
|
47
|
-
pool_max_overflow: Maximum additional connections
|
|
48
|
-
pool_timeout: Connection acquisition timeout
|
|
49
|
-
"""
|
|
50
|
-
self._database_url = database_url
|
|
51
|
-
self._pool_size = pool_size
|
|
52
|
-
self._pool_max_size = pool_size + pool_max_overflow
|
|
53
|
-
self._pool_timeout = pool_timeout
|
|
54
|
-
self._pool: ConnectionPool | None = None
|
|
55
|
-
self._local = threading.local()
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def dialect(self) -> Dialect:
|
|
59
|
-
"""Return dialect name for query selection."""
|
|
60
|
-
return "postgres"
|
|
61
|
-
|
|
62
|
-
def connect(self) -> None:
|
|
63
|
-
"""Establish database connection pool."""
|
|
64
|
-
if self._pool is not None:
|
|
65
|
-
return
|
|
66
|
-
self._pool = ConnectionPool(
|
|
67
|
-
self._database_url,
|
|
68
|
-
min_size=self._pool_size,
|
|
69
|
-
max_size=self._pool_max_size,
|
|
70
|
-
timeout=self._pool_timeout,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
def close(self) -> None:
|
|
74
|
-
"""Close database connection pool."""
|
|
75
|
-
if self._pool:
|
|
76
|
-
self._pool.close()
|
|
77
|
-
self._pool = None
|
|
78
|
-
|
|
79
|
-
def is_connected(self) -> bool:
|
|
80
|
-
"""Check if database is connected."""
|
|
81
|
-
return self._pool is not None
|
|
82
|
-
|
|
83
|
-
def _ensure_pool(self) -> ConnectionPool:
|
|
84
|
-
"""Ensure pool exists and return it."""
|
|
85
|
-
if self._pool is None:
|
|
86
|
-
raise DatabaseError("Database not connected. Call connect() first.")
|
|
87
|
-
return self._pool
|
|
88
|
-
|
|
89
|
-
def _get_current_conn(self) -> psycopg.Connection | None:
|
|
90
|
-
"""Get connection from current transaction context."""
|
|
91
|
-
return getattr(self._local, "conn", None)
|
|
92
|
-
|
|
93
|
-
@contextmanager
|
|
94
|
-
def transaction(
|
|
95
|
-
self, isolation_level: IsolationLevel | None = None
|
|
96
|
-
) -> Iterator[None]:
|
|
97
|
-
"""Context manager for database transactions.
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
isolation_level: Optional isolation level (e.g., SERIALIZABLE for nonce reservation)
|
|
101
|
-
|
|
102
|
-
Usage:
|
|
103
|
-
with db.transaction():
|
|
104
|
-
ops.intents.create_intent(db, ...)
|
|
105
|
-
|
|
106
|
-
with db.transaction(isolation_level="SERIALIZABLE"):
|
|
107
|
-
# Atomic nonce reservation
|
|
108
|
-
...
|
|
109
|
-
"""
|
|
110
|
-
if self._get_current_conn() is not None:
|
|
111
|
-
raise DatabaseError("Nested transactions are not supported")
|
|
112
|
-
|
|
113
|
-
pool = self._ensure_pool()
|
|
114
|
-
with pool.connection() as conn:
|
|
115
|
-
conn.row_factory = dict_row
|
|
116
|
-
with conn.transaction():
|
|
117
|
-
if isolation_level:
|
|
118
|
-
conn.execute(f"SET TRANSACTION ISOLATION LEVEL {isolation_level}")
|
|
119
|
-
self._local.conn = conn
|
|
120
|
-
try:
|
|
121
|
-
yield
|
|
122
|
-
finally:
|
|
123
|
-
self._local.conn = None
|
|
124
|
-
|
|
125
|
-
def execute(self, query: str, params: dict[str, Any] | None = None) -> None:
|
|
126
|
-
"""Execute a query without returning results."""
|
|
127
|
-
query = _rewrite(query)
|
|
128
|
-
conn = self._get_current_conn()
|
|
129
|
-
try:
|
|
130
|
-
if conn is not None:
|
|
131
|
-
conn.execute(query, params or {})
|
|
132
|
-
return
|
|
133
|
-
|
|
134
|
-
pool = self._ensure_pool()
|
|
135
|
-
with pool.connection() as conn:
|
|
136
|
-
conn.row_factory = dict_row
|
|
137
|
-
with conn.transaction():
|
|
138
|
-
conn.execute(query, params or {})
|
|
139
|
-
except psycopg.Error as e:
|
|
140
|
-
raise DatabaseError(f"Postgres query failed: {e}") from e
|
|
141
|
-
|
|
142
|
-
def fetch_one(
|
|
143
|
-
self, query: str, params: dict[str, Any] | None = None
|
|
144
|
-
) -> dict[str, Any] | None:
|
|
145
|
-
"""Execute a query and return single result or None."""
|
|
146
|
-
query = _rewrite(query)
|
|
147
|
-
conn = self._get_current_conn()
|
|
148
|
-
try:
|
|
149
|
-
if conn is not None:
|
|
150
|
-
return conn.execute(query, params or {}).fetchone()
|
|
151
|
-
|
|
152
|
-
pool = self._ensure_pool()
|
|
153
|
-
with pool.connection() as conn:
|
|
154
|
-
conn.row_factory = dict_row
|
|
155
|
-
with conn.transaction():
|
|
156
|
-
return conn.execute(query, params or {}).fetchone()
|
|
157
|
-
except psycopg.Error as e:
|
|
158
|
-
raise DatabaseError(f"Postgres query failed: {e}") from e
|
|
159
|
-
|
|
160
|
-
def fetch_all(
|
|
161
|
-
self, query: str, params: dict[str, Any] | None = None
|
|
162
|
-
) -> list[dict[str, Any]]:
|
|
163
|
-
"""Execute a query and return all results."""
|
|
164
|
-
query = _rewrite(query)
|
|
165
|
-
conn = self._get_current_conn()
|
|
166
|
-
try:
|
|
167
|
-
if conn is not None:
|
|
168
|
-
return conn.execute(query, params or {}).fetchall()
|
|
169
|
-
|
|
170
|
-
pool = self._ensure_pool()
|
|
171
|
-
with pool.connection() as conn:
|
|
172
|
-
conn.row_factory = dict_row
|
|
173
|
-
with conn.transaction():
|
|
174
|
-
return conn.execute(query, params or {}).fetchall()
|
|
175
|
-
except psycopg.Error as e:
|
|
176
|
-
raise DatabaseError(f"Postgres query failed: {e}") from e
|
|
177
|
-
|
|
178
|
-
def execute_rowcount(
|
|
179
|
-
self, query: str, params: dict[str, Any] | None = None
|
|
180
|
-
) -> int:
|
|
181
|
-
"""Execute a query and return affected row count."""
|
|
182
|
-
query = _rewrite(query)
|
|
183
|
-
conn = self._get_current_conn()
|
|
184
|
-
try:
|
|
185
|
-
if conn is not None:
|
|
186
|
-
cur = conn.execute(query, params or {})
|
|
187
|
-
return cur.rowcount
|
|
188
|
-
|
|
189
|
-
pool = self._ensure_pool()
|
|
190
|
-
with pool.connection() as conn:
|
|
191
|
-
conn.row_factory = dict_row
|
|
192
|
-
with conn.transaction():
|
|
193
|
-
cur = conn.execute(query, params or {})
|
|
194
|
-
return cur.rowcount
|
|
195
|
-
except psycopg.Error as e:
|
|
196
|
-
raise DatabaseError(f"Postgres query failed: {e}") from e
|