@abelxiaoxing/cadence 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@ import { validateVerificationAdapterCapability } from "./verification-capability
21
21
 
22
22
  export const IMPLEMENT_PLAN_SCHEMA_VERSION = 3 as const;
23
23
  export const IMPLEMENT_PLAN_PATH = "implement-plan.json" as const;
24
- export const DELIVERY_RECEIPT_VERSION = 3 as const;
24
+ export const DELIVERY_RECEIPT_VERSION = 4 as const;
25
25
  export const GATE_A_RECEIPT_PATH = "gate-a.yaml" as const;
26
26
  export const READY_RECEIPT_PATH = "ready.yaml" as const;
27
27
 
@@ -35,14 +35,17 @@ export interface DeliveryArtifactBinding {
35
35
  rawSha256: string;
36
36
  }
37
37
 
38
+ export interface GateApprovalProof {
39
+ revision: number;
40
+ contractHash: string;
41
+ recordHash: string;
42
+ }
43
+
38
44
  export interface GateAReceipt {
39
45
  receiptVersion: typeof DELIVERY_RECEIPT_VERSION;
40
46
  change: string;
41
47
  schema: string;
42
- approval: {
43
- approved: true;
44
- blockingDecisions: 0;
45
- };
48
+ approval: GateApprovalProof;
46
49
  artifacts: DeliveryArtifactBinding[];
47
50
  }
48
51
 
@@ -65,8 +68,9 @@ export interface ReadyReceipt {
65
68
  rawSha256: string;
66
69
  };
67
70
  gateB: {
68
- approved: true;
69
- blockingDecisions: 0;
71
+ revision: number;
72
+ contractHash: string;
73
+ recordHash: string;
70
74
  };
71
75
  };
72
76
  artifacts: DeliveryArtifactBinding[];
@@ -320,6 +324,22 @@ function requireReceiptIdentity(
320
324
  }
321
325
  }
322
326
 
327
+ function normalizeGateProof(value: GateApprovalProof): GateApprovalProof {
328
+ if (
329
+ !isRecord(value) ||
330
+ !exactKeys(value, ["revision", "contractHash", "recordHash"]) ||
331
+ !Number.isSafeInteger(value.revision) ||
332
+ value.revision < 1 ||
333
+ typeof value.contractHash !== "string" ||
334
+ !SHA256.test(value.contractHash) ||
335
+ typeof value.recordHash !== "string" ||
336
+ !SHA256.test(value.recordHash)
337
+ ) {
338
+ throw new Error("delivery-gate-proof-invalid");
339
+ }
340
+ return structuredClone(value);
341
+ }
342
+
323
343
  function parseCanonicalReceipt<T>(bytes: Uint8Array, code: string): T {
324
344
  const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
325
345
  let parsed: unknown;
@@ -335,6 +355,7 @@ function parseCanonicalReceipt<T>(bytes: Uint8Array, code: string): T {
335
355
  export function compileGateAReceipt(input: {
336
356
  change: string;
337
357
  schema: string;
358
+ approval: GateApprovalProof;
338
359
  artifacts: readonly DeliveryArtifactBinding[];
339
360
  }): { receipt: GateAReceipt; bytes: Uint8Array; rawSha256: string } {
340
361
  requireReceiptIdentity(input.change, input.schema);
@@ -342,7 +363,7 @@ export function compileGateAReceipt(input: {
342
363
  receiptVersion: DELIVERY_RECEIPT_VERSION,
343
364
  change: input.change,
344
365
  schema: input.schema,
345
- approval: { approved: true, blockingDecisions: 0 },
366
+ approval: normalizeGateProof(input.approval),
346
367
  artifacts: normalizeArtifactBindings(input.artifacts),
347
368
  };
348
369
  const bytes = canonicalBytes(receipt);
@@ -369,15 +390,17 @@ export function parseGateAReceipt(bytes: Uint8Array): GateAReceipt {
369
390
  ]) ||
370
391
  receipt.receiptVersion !== DELIVERY_RECEIPT_VERSION ||
371
392
  !isRecord(receipt.approval) ||
372
- !exactKeys(receipt.approval, ["approved", "blockingDecisions"]) ||
373
- receipt.approval.approved !== true ||
374
- receipt.approval.blockingDecisions !== 0
393
+ !exactKeys(receipt.approval, ["revision", "contractHash", "recordHash"])
375
394
  ) {
376
395
  throw new Error("gate-a-receipt-invalid");
377
396
  }
378
397
  requireReceiptIdentity(receipt.change, receipt.schema);
398
+ const approval = normalizeGateProof(receipt.approval);
379
399
  const artifacts = normalizeArtifactBindings(receipt.artifacts);
380
- if (canonicalJson(artifacts) !== canonicalJson(receipt.artifacts)) {
400
+ if (
401
+ canonicalJson(approval) !== canonicalJson(receipt.approval) ||
402
+ canonicalJson(artifacts) !== canonicalJson(receipt.artifacts)
403
+ ) {
381
404
  throw new Error("gate-a-receipt-invalid");
382
405
  }
383
406
  return structuredClone(receipt);
@@ -415,6 +438,7 @@ export function compileReadyReceipt(input: {
415
438
  schema: string;
416
439
  deliveryRevision: number;
417
440
  gateA: { rawSha256: string };
441
+ gateB: GateApprovalProof;
418
442
  artifacts: readonly DeliveryArtifactBinding[];
419
443
  compiledPlan: CompiledDelivery;
420
444
  traceability: DeliveryTraceability;
@@ -424,7 +448,8 @@ export function compileReadyReceipt(input: {
424
448
  !Number.isSafeInteger(input.deliveryRevision) ||
425
449
  input.deliveryRevision < 1 ||
426
450
  !SHA256.test(input.gateA.rawSha256) ||
427
- input.compiledPlan.plan.changeId !== input.change
451
+ input.compiledPlan.plan.changeId !== input.change ||
452
+ input.gateB.contractHash !== input.compiledPlan.planHash
428
453
  ) {
429
454
  throw new Error("delivery-receipt-invalid");
430
455
  }
@@ -438,7 +463,7 @@ export function compileReadyReceipt(input: {
438
463
  path: GATE_A_RECEIPT_PATH,
439
464
  rawSha256: input.gateA.rawSha256,
440
465
  },
441
- gateB: { approved: true, blockingDecisions: 0 },
466
+ gateB: normalizeGateProof(input.gateB),
442
467
  },
443
468
  artifacts: normalizeArtifactBindings(input.artifacts),
444
469
  plan: structuredClone(input.compiledPlan.receipt.plan),
@@ -485,9 +510,11 @@ export function parseReadyReceipt(bytes: Uint8Array): ReadyReceipt {
485
510
  receipt.approvals.gateA.path !== GATE_A_RECEIPT_PATH ||
486
511
  !SHA256.test(receipt.approvals.gateA.rawSha256) ||
487
512
  !isRecord(receipt.approvals.gateB) ||
488
- !exactKeys(receipt.approvals.gateB, ["approved", "blockingDecisions"]) ||
489
- receipt.approvals.gateB.approved !== true ||
490
- receipt.approvals.gateB.blockingDecisions !== 0 ||
513
+ !exactKeys(receipt.approvals.gateB, [
514
+ "revision",
515
+ "contractHash",
516
+ "recordHash",
517
+ ]) ||
491
518
  !isRecord(receipt.plan) ||
492
519
  !exactKeys(receipt.plan, [
493
520
  "path",
@@ -513,8 +540,11 @@ export function parseReadyReceipt(bytes: Uint8Array): ReadyReceipt {
513
540
  }
514
541
  requireReceiptIdentity(receipt.change, receipt.schema);
515
542
  const artifacts = normalizeArtifactBindings(receipt.artifacts);
543
+ const gateB = normalizeGateProof(receipt.approvals.gateB);
516
544
  const traceability = normalizeTraceability(receipt.traceability);
517
545
  if (
546
+ gateB.contractHash !== receipt.plan.canonicalHash ||
547
+ canonicalJson(gateB) !== canonicalJson(receipt.approvals.gateB) ||
518
548
  canonicalJson(artifacts) !== canonicalJson(receipt.artifacts) ||
519
549
  canonicalJson(traceability) !== canonicalJson(receipt.traceability)
520
550
  ) {