fix: wait out processing until the certificate exists

A global stamp now polls status processing the same way as pending
and returns only the completed result. The debug trace for
Verae-Debug-Test records one receipt id.
This commit is contained in:
George Lambert 2026-09-23 11:37:13 -04:00
commit b89c4ad4d2
5 changed files with 4446 additions and 6 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -375,14 +375,14 @@ class GlobalClient:
raise ValueError(f"global timestamp HTTP {res.status_code}: {res.text}")
if not isinstance(parsed, dict):
parsed = {}
job_id = parsed.get("jobId") or parsed.get("blockHash") or ""
job_id = str(parsed.get("jobId") or parsed.get("blockHash") or "")
if not job_id:
raise ValueError("global timestamp response missing jobId")
created = str(parsed.get("timestamp") or "")
merkle = str(parsed.get("blockHash") or "")
receipt_id = str(job_id)
receipt_id = ""
status_url = f"{self.base_url}/api/status/{job_id}"
for _ in range(20):
for _ in range(40):
st = self.http.request("GET", status_url, payload={}, headers=self._headers())
if st.status_code >= 300:
break
@ -393,15 +393,19 @@ class GlobalClient:
if state == "failed":
raise ValueError(str(body.get("error") or "global timestamp job failed"))
if state == "completed":
receipt_id = str(body.get("result") or body.get("id") or job_id)
receipt_id = str(body.get("result") or "")
meta = body.get("metadata") or {}
created = str(meta.get("timestamp") or body.get("completedAt") or created)
merkle = str(meta.get("blockIndex") or meta.get("blockHash") or merkle)
if receipt_id:
break
if state in ("pending", "running", ""):
receipt_id = ""
if state in ("pending", "running", "processing", ""):
time.sleep(0.25)
continue
break
if not receipt_id:
raise ValueError(f"global timestamp job {job_id} not completed")
return Receipt(
receipt_id=receipt_id,
hash=digest,

View file

@ -97,6 +97,38 @@ async def test_existing_digest_returns_first_certificate_without_status_poll():
assert len(http.calls) == 1
async def test_processing_status_polls_until_certificate():
class ProcessingHttp(FakeHttp):
def __init__(self):
super().__init__()
self.status_calls = 0
def request(self, method, url, payload, headers):
self.calls.append((method, url, payload, headers))
if url.endswith("/api/timestamp"):
return _Resp(202, {"jobId": "job-p"})
if url.endswith("/api/status/job-p"):
self.status_calls += 1
if self.status_calls < 3:
return _Resp(200, {"id": "job-p", "status": "processing"})
return _Resp(
200,
{
"id": "job-p",
"status": "completed",
"result": "QmDone",
"metadata": {"timestamp": "2026-09-23T00:00:00Z", "blockHash": "0xabc"},
},
)
return _Resp(404, {"error": "nope"})
http = ProcessingHttp()
rec = GlobalClient("https://api.veraetime.net", http=http).submit(SHA256_EMPTY)
assert rec.receipt_id == "QmDone"
assert rec.receipt_id != "job-p"
assert http.status_calls == 3
async def test_existing_without_certificate_polls_job():
class PendingExisting(FakeHttp):
def request(self, method, url, payload, headers):