fix(tracker): close alpha accounting review gaps

Address post-review blockers from the alpha hardening diff: charge non-stream completions that omit usage, include prompt tokens in max_charge_per_request enforcement, and wire the CLI to a persisted local registry contract by default.

Verification: .venv/bin/python -m compileall -q packages tests; focused billing/CLI checks passed; full pytest: 314 passed, 3 skipped, 1 env failure from existing meshnet-node on port 7000.
This commit is contained in:
Dobromir Popov
2026-07-05 21:55:07 +03:00
parent 9abe83b5f4
commit de6ce1d514
3 changed files with 87 additions and 22 deletions

View File

@@ -8,6 +8,8 @@ from .accounts import DEFAULT_ACCOUNTS_DB_PATH
from .billing import DEFAULT_BILLING_DB_PATH
from .server import TrackerServer, derive_relay_url_from_public_tracker_url
DEFAULT_REGISTRY_DB_PATH = "meshnet_registry.sqlite3"
def main() -> None:
common = argparse.ArgumentParser(add_help=False)
@@ -49,20 +51,34 @@ def main() -> None:
f"(default: {DEFAULT_BILLING_DB_PATH}; ADR-0015)"
),
)
common.add_argument(
"--no-billing",
action="store_true",
help="Disable the USDT billing ledger",
)
common.add_argument(
"--max-charge-per-request",
type=float,
default=None,
help=(
"Reject chat completion requests whose requested token limit would "
"cost more than this many USDT"
),
)
common.add_argument(
"--no-billing",
action="store_true",
help="Disable the USDT billing ledger",
)
common.add_argument(
"--max-charge-per-request",
type=float,
default=None,
help=(
"Reject chat completion requests whose prompt plus requested completion "
"token bound would cost more than this many USDT"
),
)
common.add_argument(
"--registry-db",
default=DEFAULT_REGISTRY_DB_PATH,
metavar="PATH",
help=(
"SQLite database path for persisted strike/ban/reputation registry "
f"state (default: {DEFAULT_REGISTRY_DB_PATH})"
),
)
common.add_argument(
"--no-registry-contracts",
action="store_true",
help="Disable the local contract registry used for strike/ban/reputation enforcement",
)
common.add_argument(
"--accounts-db",
default=DEFAULT_ACCOUNTS_DB_PATH,
@@ -149,6 +165,11 @@ def main() -> None:
treasury = SolanaCustodialTreasury(
args.solana_rpc_url, args.usdt_mint, args.treasury_keypair,
)
contracts = None
if not args.no_registry_contracts:
from meshnet_contracts import LocalSolanaContracts # type: ignore[import-not-found]
contracts = LocalSolanaContracts(registry_db=args.registry_db)
server = TrackerServer(
host=args.host,
port=args.port,
@@ -158,9 +179,10 @@ def main() -> None:
stats_db=getattr(args, "stats_db", None),
relay_url=relay_url,
enable_billing=not args.no_billing,
billing_db=None if args.no_billing else args.billing_db,
max_charge_per_request=args.max_charge_per_request,
accounts_db=None if args.no_accounts else args.accounts_db,
billing_db=None if args.no_billing else args.billing_db,
max_charge_per_request=args.max_charge_per_request,
contracts=contracts,
accounts_db=None if args.no_accounts else args.accounts_db,
treasury=treasury,
settle_period=args.settle_period,
payout_threshold=args.payout_threshold,

View File

@@ -1293,15 +1293,43 @@ def _request_total_token_upper_bound(body: dict) -> int | None:
def _billable_non_stream_tokens(payload: dict, request_body: dict) -> int:
reported = _usage_total_tokens(payload)
if reported is None:
return 0
billable = max(0, reported)
upper_bound = _request_total_token_upper_bound(request_body)
if reported is None:
completion_estimate = _observed_non_stream_completion_tokens(payload)
if completion_estimate > 0:
billable = completion_estimate + (_estimate_prompt_tokens(request_body) or 0)
elif upper_bound is not None:
billable = upper_bound
else:
return 0
return min(billable, upper_bound) if upper_bound is not None else billable
billable = max(0, reported)
if upper_bound is not None:
billable = min(billable, upper_bound)
return billable
def _observed_non_stream_completion_tokens(payload: dict) -> int:
choices = payload.get("choices")
if not isinstance(choices, list):
return 0
observed = 0
for choice in choices:
if not isinstance(choice, dict):
continue
message = choice.get("message")
estimated: int | None = None
if isinstance(message, dict):
estimated = _estimate_text_tokens(message.get("content"))
if estimated is None:
estimated = _estimate_text_tokens(choice.get("text"))
if estimated is not None:
observed += estimated
elif choice:
observed += 1
return observed
def _observed_stream_tokens(payload: dict) -> int:
choices = payload.get("choices")
if not isinstance(choices, list):
@@ -1881,7 +1909,8 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
"code": "missing_token_limit",
}})
return
estimated_charge = server.billing.price_for(model) * token_limit / 1000.0
total_token_bound = _request_total_token_upper_bound(body) or token_limit
estimated_charge = server.billing.price_for(model) * total_token_bound / 1000.0
if estimated_charge > server.max_charge_per_request:
self._send_json(402, {"error": {
"message": (