Skip to content

tools: a reference Facilitator, party agents, and a measurement harness - #10

Open
laxsharma wants to merge 1 commit into
mainfrom
reference-implementation
Open

tools: a reference Facilitator, party agents, and a measurement harness#10
laxsharma wants to merge 1 commit into
mainfrom
reference-implementation

Conversation

@laxsharma

Copy link
Copy Markdown
Member

Section 15 of the draft says no Facilitator, Buyer or Seller exchanging messages over the Section 12 endpoints is known to me. This is one. It is not the experiment Section 1.4 describes, which needs two independent implementations settling each other's contracts, so treat this as the first half and an invitation for the second.

What it is. facilitator.py serves the six operations of Table 1 over five paths, runs the Figure 2 state machine, checks the Section 7.2 assurance constraint before locking funds, applies the five-rank Section 7.4 waterfall, issues a Facilitator-signed attestation for every terminal contract, and refuses with RFC 9457 problem documents that name the rule that was violated. agents.py is the party side. pactcore.py holds canonicalization, JWS, normalization and the constraint. measure.py drives it.

Signatures are real Ed25519 over the Section 13.1 signing input, which is computed over the object with its signing member removed while vtc_hash is computed over the object with signatures included. Both constructions are exercised.

The committed examples keep their placeholder signatures on purpose. The published draft prints their digests in Section 14 and cannot be corrected, so re-signing them would silently desynchronise this repository from that document. measure.py mints fresh keys and contracts instead, and those validate against the published schemas.

What running it found. Two defects, both in the specification rather than the code.

Section 6 introduces the missed-deadline rule with the sentence "This is the rule that makes silence expensive", and then slashes the bond only to the extent of restitution_basis. The worked example sets that member to released, and under the default on-verification release nothing is released before a verdict, so the extent is zero. The seller signs, posts a bond, delivers nothing, and gets the whole bond back.

Section 7.4 has the same hole for the same reason. Rank 3 restitution is measured against the same member, so it is zero, and the bond falls through to rank 5 and the neutral sink. That is precisely the -00 behaviour Section 7.4 was written to correct, reproduced by the -01's own example. Changing the member to price pays the buyer 18.00 out of the bond for the same fraud.

Neither is fixed here, because both are -02 questions: either the example should use price, or the member needs a stated default plus a rule that a Facilitator refuses a combination that makes the remedy vacuous.

Measured on the machine noted in the output. Three terminal states in four, four and three messages, under 3.1 kB on the wire per contract. Ed25519 verification of a contract around 0.57 ms and canonicalize-plus-digest around 0.14 ms, against 625 ms for the T0-reexec acceptance harness, so verification cost sits in the profile and not in the protocol by about three orders of magnitude.

validate.py is untouched and still passes its 66 checks. cryptography is an optional dependency it does not need.

Section 15 says no Facilitator, Buyer or Seller exchanging messages over
the Section 12 endpoints is known to the author. That is now half wrong:
this is one such implementation. Two independent ones settling each
other's contracts is still the experiment Section 1.4 describes.

facilitator.py serves the six operations of Table 1 over five paths, runs
the Figure 2 state machine, evaluates the Section 7.2 constraint before
locking funds, applies the Section 7.4 waterfall, issues a Facilitator
signed attestation for every terminal contract, and refuses with RFC 9457
problem documents that name the rule. agents.py is the Buyer, Seller and
Verifier side. measure.py drives three contracts to FINAL, SETTLED and
ABANDONED, exercises eight refusal paths, and reports costs.

Signatures are real Ed25519 over the Section 13.1 signing input. The
committed examples keep their placeholder values on purpose: the
published draft prints their digests in Section 14 and cannot be
corrected, so re-signing them would desynchronise this repository from
that document. measure.py mints fresh keys and fresh contracts instead,
and they validate against the published schemas.

Running it found two specification defects, both recorded in
tools/README.md and both -02 items rather than code changes.

Section 6 introduces the missed-deadline rule with "This is the rule that
makes silence expensive", then slashes the bond only to the extent of
restitution_basis. The worked example sets that to "released", and under
the default on-verification release nothing is released before a verdict,
so the extent is zero. A seller can sign, post a bond, deliver nothing,
and get the entire bond back.

Section 7.4 has the same hole. Rank 3 restitution is measured against the
same member, so it is also zero, and the bond falls through to rank 5 and
the neutral sink. That is the exact -00 behaviour Section 7.4 exists to
correct, reproduced by the -01's own worked example. Setting the member to
"price" pays the buyer 18.00 from the bond instead.

validate.py is untouched and still passes its 66 checks; cryptography
stays an optional dependency it does not need.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant