Skip to content

Commit 4322803

Browse files
committed
Defer to DBWrapper2
1 parent b2aab8a commit 4322803

File tree

4 files changed

+24
-59
lines changed

4 files changed

+24
-59
lines changed

chia/_tests/blockchain/test_blockchain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3879,7 +3879,7 @@ async def test_chain_failed_rollback(empty_blockchain: Blockchain, bt: BlockTool
38793879
print(f"{await b.consensus_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
38803880
print(spend_bundle.coin_spends[0].coin.name())
38813881
# await b.consensus_store._set_spent([spend_bundle.coin_spends[0].coin.name()], 8)
3882-
async with b.consensus_store as writer:
3882+
async with b.consensus_store.writer() as writer:
38833883
await writer.rollback_to_block(2)
38843884
print(f"{await b.consensus_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
38853885

chia/consensus/blockchain.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ async def add_block(
413413

414414
try:
415415
# Always add the block to the database
416-
async with self.consensus_store as writer:
416+
async with self.consensus_store.writer() as writer:
417417
# Perform the DB operations to update the state, and rollback if something goes wrong
418418
await writer.add_full_block(header_hash, block, block_record)
419419
records, state_change_summary = await self._reconsider_peak(block_record, genesis, fork_info)
@@ -486,7 +486,7 @@ async def _reconsider_peak(
486486
if genesis and peak is not None:
487487
return [], None
488488

489-
async with self.consensus_store as writer:
489+
async with self.consensus_store.writer() as writer:
490490
if peak is not None:
491491
if block_record.weight < peak.weight:
492492
# This is not a heavier block than the heaviest we have seen, so we don't change the coin set
@@ -981,7 +981,7 @@ def add_block_record(self, block_record: BlockRecord) -> None:
981981
async def persist_sub_epoch_challenge_segments(
982982
self, ses_block_hash: bytes32, segments: list[SubEpochChallengeSegment]
983983
) -> None:
984-
async with self.consensus_store as writer:
984+
async with self.consensus_store.writer() as writer:
985985
await writer.persist_sub_epoch_challenge_segments(ses_block_hash, segments)
986986

987987
async def get_sub_epoch_challenge_segments(

chia/consensus/consensus_store_protocol.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

33
from collections.abc import Collection
4-
from types import TracebackType
54
from typing import Optional, Protocol
65

76
from chia_rs import BlockRecord, FullBlock, SubEpochChallengeSegment, SubEpochSummary
87
from chia_rs.sized_bytes import bytes32
98
from chia_rs.sized_ints import uint32, uint64
9+
from typing_extensions import AsyncContextManager
1010

1111
from chia.types.blockchain_format.coin import Coin
1212
from chia.types.coin_record import CoinRecord
@@ -46,28 +46,22 @@ class ConsensusStoreProtocol(Protocol):
4646
"""
4747
Read-only protocol for the consensus store.
4848
49-
This protocol also acts as an async context manager. Entering the context
49+
This protocol is callable and returns an async context manager. Entering the context
5050
yields a ConsensusStoreWriteProtocol instance, which must be used for
5151
performing write (mutating) operations. This ensures atomic writes and
5252
makes it harder to accidentally perform writes outside a transaction.
5353
5454
Example usage:
55-
async with store as writer:
55+
async with store.writer() as writer:
5656
await writer.add_full_block(...)
5757
await writer.set_peak(...)
5858
5959
# Outside the context, only read methods are available
6060
br = await store.get_block_record(header_hash)
6161
"""
6262

63-
# Async context manager methods
64-
async def __aenter__(self) -> ConsensusStoreWriteProtocol: ...
65-
async def __aexit__(
66-
self,
67-
exc_type: Optional[type[BaseException]],
68-
exc: Optional[BaseException],
69-
tb: Optional[TracebackType],
70-
) -> Optional[bool]: ...
63+
# Writer method that returns async context manager
64+
def writer(self) -> AsyncContextManager[ConsensusStoreWriteProtocol]: ...
7165

7266
# Block store reads
7367
async def get_block_records_close_to_peak(

chia/full_node/consensus_store_sqlite3.py

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
from __future__ import annotations
22

3-
from collections.abc import Collection
4-
from contextlib import AbstractAsyncContextManager
3+
from collections.abc import AsyncIterator, Collection
4+
from contextlib import asynccontextmanager
55
from dataclasses import dataclass
66
from pathlib import Path
7-
from types import TracebackType
8-
from typing import TYPE_CHECKING, Any, Optional
7+
from typing import TYPE_CHECKING, Optional
98

109
from chia_rs import BlockRecord, FullBlock, SubEpochChallengeSegment, SubEpochSummary
1110
from chia_rs.sized_bytes import bytes32
@@ -55,6 +54,12 @@ async def new_block(
5554
) -> None:
5655
await self.coin_store.new_block(height, timestamp, included_reward_coins, tx_additions, tx_removals)
5756

57+
@asynccontextmanager
58+
async def writer(self) -> AsyncIterator[ConsensusStoreSQLite3Writer]:
59+
# Return self as the writer facade
60+
async with self.block_store.transaction():
61+
yield self
62+
5863

5964
@dataclass
6065
class ConsensusStoreSQLite3:
@@ -66,11 +71,6 @@ class ConsensusStoreSQLite3:
6671
coin_store: CoinStoreProtocol
6772
height_map: BlockHeightMap
6873

69-
# Writer context and writer facade for transactional writes (re-entrant via depth counter)
70-
_writer_ctx: Optional[AbstractAsyncContextManager[Any]] = None
71-
_writer: Optional[ConsensusStoreSQLite3Writer] = None
72-
_txn_depth: int = 0
73-
7474
@classmethod
7575
async def create(
7676
cls,
@@ -99,41 +99,12 @@ async def create(
9999
height_map=height_map,
100100
)
101101

102-
# Async context manager yielding a writer for atomic writes
103-
async def __aenter__(self) -> ConsensusStoreSQLite3Writer:
104-
# Re-entrant async context manager:
105-
# Begin a transaction only at the outermost level. CoinStore shares the same DB.
106-
if self._writer is None:
107-
self._writer_ctx = self.block_store.transaction()
108-
await self._writer_ctx.__aenter__()
109-
# Create writer facade bound to this transaction
110-
self._writer = ConsensusStoreSQLite3Writer(self.block_store, self.coin_store)
111-
self._txn_depth += 1
112-
return self._writer # Return the same writer for nested contexts
113-
114-
async def __aexit__(
115-
self,
116-
exc_type: Optional[type[BaseException]],
117-
exc: Optional[BaseException],
118-
tb: Optional[TracebackType],
119-
) -> Optional[bool]:
120-
try:
121-
# Check if we're at the outermost level before decrementing
122-
if self._txn_depth == 1:
123-
# This is the outermost context, handle transaction exit
124-
if self._writer_ctx is not None:
125-
return await self._writer_ctx.__aexit__(exc_type, exc, tb)
126-
return None
127-
else:
128-
# This is a nested context, just return None (don't suppress exceptions)
129-
return None
130-
finally:
131-
# Always decrement depth and clean up if we're at the outermost level
132-
if self._txn_depth > 0:
133-
self._txn_depth -= 1
134-
if self._txn_depth == 0:
135-
self._writer_ctx = None
136-
self._writer = None
102+
@asynccontextmanager
103+
async def writer(self) -> AsyncIterator[ConsensusStoreSQLite3Writer]:
104+
"""Async context manager that yields a writer facade for performing transactional writes."""
105+
csw = ConsensusStoreSQLite3Writer(self.block_store, self.coin_store)
106+
async with csw.writer() as writer:
107+
yield writer
137108

138109
# Block store methods
139110

0 commit comments

Comments
 (0)