Reject unserializable proof metadata values#257
Conversation
weilixiong
left a comment
There was a problem hiding this comment.
Review ✅ APPROVED
LOW — rejects unserializable proof metadata via canonical_json. Clean validation. MW #219.
Thanhdn1984
left a comment
There was a problem hiding this comment.
Reviewed for bounty #219.
Evidence checked:
app/ledger/service.pynow validates the cleanedverifier_resultwithcanonical_json(clean)before writing the proof metadata.- The new test covers an
object()value, expectsLedgerError, and verifies no payout/submission/proof side effects plus unchanged reserve balance.
Result: looks correct and aligned with the issue. No changes requested.
MolhamHamwi
left a comment
There was a problem hiding this comment.
No blockers found on current head 8dd1502.
Evidence checked:
- Inspected
app/ledger/service.py::_clean_proof_metadata(); the newcanonical_json(clean)validation runs before returning metadata, so unserializable values fail before proof/submission rows are created. - Confirmed the raised
LedgerErrorwrapsTypeError/ValueErrorfrom JSON canonicalization and leaves the existing control-character validation path intact. - Inspected
tests/test_ledger.py; the regression exercisespay_bounty()with anobject()metadata value and verifies no award count, balance, submission, or proof side effects are persisted. - Ran
pytest tests/test_ledger.py -q(17 passed),ruff check app/ledger/service.py tests/test_ledger.py,ruff format --check app/ledger/service.py tests/test_ledger.py, andgit diff --check origin/main...HEAD.
No secrets, wallet/private-key material, payout credentials, private deployment values, private vulnerability details, or MRWK price claims were reviewed or disclosed.
|
No blockers from my review. Evidence checked:
The added guard converts the previous serialization failure class into a controlled |
TateLyman
left a comment
There was a problem hiding this comment.
No blockers from my pass. The metadata guard catches JSON-canonicalization failures before payout mutation, which is the right boundary for proof payload integrity.
Evidence checked:
- Inspected
_clean_proof_metadata()inapp/ledger/service.py; the newcanonical_json(clean)call runs after control-character validation and before returning metadata to the payout/proof creation path. - Inspected
tests/test_ledger.py; the regression drivespay_bounty()with anobject()metadata value and then verifies no awards, submission, proof, contributor balance, or reserve balance side effects. - Ran
uv run pytest tests/test_ledger.py::test_pay_bounty_rejects_non_json_serializable_verifier_result_values tests/test_ledger.py::test_bounty_reserve_and_payout_conserve_supply -q-> 2 passed. - Ran
uv run ruff check app/ledger/service.py tests/test_ledger.py,uv run ruff format --check app/ledger/service.py tests/test_ledger.py,uv run mypy app, andgit diff --check origin/main...HEAD-> passed. - Checked hosted
Quality, readiness, docs, and image checksmetadata -> success.
Non-blocking note: this is focused on value serializability; separate key-shape validation remains covered by the neighboring proof-metadata-key work.
Bounty #228
Summary
verifier_resultdictionaries that contain values canonical JSON cannot serialize.LedgerErrorbefore payout submission/proof rows or award counters are mutated.{"label": "mrwk:accepted", "raw": object()}that verifies no payment state is recorded.Repro before fix
A direct
pay_bounty()call withverifier_result={"label": "mrwk:accepted", "raw": object()}raised a rawTypeError: Object of type object is not JSON serializablewhile building proof metadata, instead of failing closed with a ledger validation error before payout state changes.This is distinct from the existing non-string metadata-key and non-object metadata-shape PRs: this PR covers JSON-incompatible values inside an otherwise object-shaped metadata dict.
Verification
uv run --python 3.12 --extra dev python -m pytest tests/test_ledger.py::test_pay_bounty_rejects_non_json_serializable_verifier_result_values -qfailed with the rawTypeError.uv run --python 3.12 --extra dev python -m pytest tests/test_ledger.py::test_pay_bounty_rejects_non_json_serializable_verifier_result_values -q-> 1 passeduv run --python 3.12 --extra dev python -m pytest tests/test_ledger.py -q-> 17 passeduv run --python 3.12 --extra dev python -m pytest -q-> 206 passed, 2 warningsuv run --python 3.12 --extra dev ruff format --check .-> 37 files already formatteduv run --python 3.12 --extra dev ruff check .-> all checks passeduv run --python 3.12 --extra dev python -m mypy app-> successuv run --python 3.12 --extra dev python scripts/docs_smoke.py-> docs smoke okuv run --python 3.12 --extra dev python scripts/check_agents.py-> AGENTS.md okgit diff --check-> cleanNo secrets, wallet material, private vulnerability details, deployment values, payout details, or MRWK price claims are included.