Skip to content

Commit 5d76710

Browse files
authored
Merge pull request #71 from ChainSafe/fix/billing-topup-api-fix
fix: billing topup fix
2 parents 5efc17d + 1f85b9a commit 5d76710

1 file changed

Lines changed: 53 additions & 14 deletions

File tree

src/canton_mcp_server/canton_billing.py

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ async def _query_active_contracts_via_updates(
730730
party: str,
731731
extract: Callable[[str, dict, str], Optional[_T]],
732732
stop_when: Optional[Callable[[_T], bool]] = None,
733-
page_size: int = 1000,
733+
page_size: int = 100,
734734
end_offset: Optional[int] = None,
735735
) -> list[_T]:
736736
"""
@@ -780,7 +780,59 @@ async def _query_active_contracts_via_updates(
780780
break
781781

782782
max_offset_this_page = begin
783+
784+
def _item_offset(item: dict) -> Optional[int]:
785+
"""Return the offset for any update variant (Transaction,
786+
OffsetCheckpoint, Reassignment, TopologyTransaction, ...) so the
787+
cursor advances even on pages that contain no Transactions. If we
788+
only looked at Transactions, a page of pure OffsetCheckpoints
789+
would leave `max_offset_this_page == begin` and the outer loop
790+
would break prematurely — missing all later transactions.
791+
"""
792+
upd = item.get("update", {}) if isinstance(item, dict) else {}
793+
if not isinstance(upd, dict):
794+
return None
795+
# Try every known variant wrapper, both capitalized and flat.
796+
for variant in (
797+
"Transaction",
798+
"OffsetCheckpoint",
799+
"Reassignment",
800+
"TopologyTransaction",
801+
):
802+
wrapper = upd.get(variant)
803+
if isinstance(wrapper, dict):
804+
value = wrapper.get("value")
805+
if isinstance(value, dict) and value.get("offset") is not None:
806+
return _coerce_offset(value.get("offset"))
807+
for variant in (
808+
"transaction",
809+
"offsetCheckpoint",
810+
"reassignment",
811+
"topologyTransaction",
812+
):
813+
value = upd.get(variant)
814+
if isinstance(value, dict) and value.get("offset") is not None:
815+
return _coerce_offset(value.get("offset"))
816+
return None
817+
818+
def _coerce_offset(raw) -> Optional[int]:
819+
if isinstance(raw, (int, float)):
820+
return int(raw)
821+
if isinstance(raw, str):
822+
try:
823+
return int(raw)
824+
except ValueError:
825+
return None
826+
return None
827+
783828
for item in items:
829+
# Always try to advance the page cursor — regardless of whether
830+
# the item is a Transaction. This is the fix for checkpoint-only
831+
# pages that would otherwise terminate the walk prematurely.
832+
item_off = _item_offset(item)
833+
if item_off is not None and item_off > max_offset_this_page:
834+
max_offset_this_page = item_off
835+
784836
update = item.get("update", {}) if isinstance(item, dict) else {}
785837
tx_wrapper = update.get("Transaction") or {}
786838
tx = tx_wrapper.get("value") if isinstance(tx_wrapper, dict) else None
@@ -789,19 +841,6 @@ async def _query_active_contracts_via_updates(
789841
if not tx:
790842
continue
791843

792-
raw_offset = tx.get("offset")
793-
if isinstance(raw_offset, str):
794-
try:
795-
tx_offset = int(raw_offset)
796-
except ValueError:
797-
tx_offset = max_offset_this_page
798-
elif isinstance(raw_offset, (int, float)):
799-
tx_offset = int(raw_offset)
800-
else:
801-
tx_offset = max_offset_this_page
802-
if tx_offset > max_offset_this_page:
803-
max_offset_this_page = tx_offset
804-
805844
for ev in tx.get("events", []) or []:
806845
created = ev.get("CreatedEvent") or ev.get("createdEvent")
807846
if created:

0 commit comments

Comments
 (0)