@optimystic/db-core 0.5.2 → 0.7.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.
Files changed (93) hide show
  1. package/dist/src/btree/btree.d.ts +2 -0
  2. package/dist/src/btree/btree.d.ts.map +1 -1
  3. package/dist/src/btree/btree.js +72 -52
  4. package/dist/src/btree/btree.js.map +1 -1
  5. package/dist/src/cluster/structs.d.ts +13 -0
  6. package/dist/src/cluster/structs.d.ts.map +1 -1
  7. package/dist/src/collection/collection.d.ts +10 -0
  8. package/dist/src/collection/collection.d.ts.map +1 -1
  9. package/dist/src/collection/collection.js +34 -0
  10. package/dist/src/collection/collection.js.map +1 -1
  11. package/dist/src/index.d.ts +1 -0
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/index.js +1 -0
  14. package/dist/src/index.js.map +1 -1
  15. package/dist/src/log/log.js +1 -1
  16. package/dist/src/log/log.js.map +1 -1
  17. package/dist/src/logger.d.ts +4 -0
  18. package/dist/src/logger.d.ts.map +1 -0
  19. package/dist/src/logger.js +8 -0
  20. package/dist/src/logger.js.map +1 -0
  21. package/dist/src/transaction/coordinator.d.ts +31 -8
  22. package/dist/src/transaction/coordinator.d.ts.map +1 -1
  23. package/dist/src/transaction/coordinator.js +206 -53
  24. package/dist/src/transaction/coordinator.js.map +1 -1
  25. package/dist/src/transaction/index.d.ts +2 -2
  26. package/dist/src/transaction/index.d.ts.map +1 -1
  27. package/dist/src/transaction/index.js +1 -1
  28. package/dist/src/transaction/index.js.map +1 -1
  29. package/dist/src/transaction/session.d.ts +11 -7
  30. package/dist/src/transaction/session.d.ts.map +1 -1
  31. package/dist/src/transaction/session.js +27 -14
  32. package/dist/src/transaction/session.js.map +1 -1
  33. package/dist/src/transaction/transaction.d.ts +9 -3
  34. package/dist/src/transaction/transaction.d.ts.map +1 -1
  35. package/dist/src/transaction/transaction.js +14 -7
  36. package/dist/src/transaction/transaction.js.map +1 -1
  37. package/dist/src/transaction/validator.d.ts +9 -2
  38. package/dist/src/transaction/validator.d.ts.map +1 -1
  39. package/dist/src/transaction/validator.js +26 -6
  40. package/dist/src/transaction/validator.js.map +1 -1
  41. package/dist/src/transactor/network-transactor.d.ts.map +1 -1
  42. package/dist/src/transactor/network-transactor.js +84 -9
  43. package/dist/src/transactor/network-transactor.js.map +1 -1
  44. package/dist/src/transactor/transactor-source.d.ts +4 -0
  45. package/dist/src/transactor/transactor-source.d.ts.map +1 -1
  46. package/dist/src/transactor/transactor-source.js +25 -9
  47. package/dist/src/transactor/transactor-source.js.map +1 -1
  48. package/dist/src/transform/atomic-proxy.d.ts +26 -0
  49. package/dist/src/transform/atomic-proxy.d.ts.map +1 -0
  50. package/dist/src/transform/atomic-proxy.js +47 -0
  51. package/dist/src/transform/atomic-proxy.js.map +1 -0
  52. package/dist/src/transform/cache-source.d.ts +3 -2
  53. package/dist/src/transform/cache-source.d.ts.map +1 -1
  54. package/dist/src/transform/cache-source.js +15 -3
  55. package/dist/src/transform/cache-source.js.map +1 -1
  56. package/dist/src/transform/index.d.ts +1 -0
  57. package/dist/src/transform/index.d.ts.map +1 -1
  58. package/dist/src/transform/index.js +1 -0
  59. package/dist/src/transform/index.js.map +1 -1
  60. package/dist/src/utility/batch-coordinator.d.ts +2 -0
  61. package/dist/src/utility/batch-coordinator.d.ts.map +1 -1
  62. package/dist/src/utility/batch-coordinator.js +6 -1
  63. package/dist/src/utility/batch-coordinator.js.map +1 -1
  64. package/dist/src/utility/hash-string.d.ts +3 -6
  65. package/dist/src/utility/hash-string.d.ts.map +1 -1
  66. package/dist/src/utility/hash-string.js +8 -11
  67. package/dist/src/utility/hash-string.js.map +1 -1
  68. package/dist/src/utility/lru-map.d.ts +18 -0
  69. package/dist/src/utility/lru-map.d.ts.map +1 -0
  70. package/dist/src/utility/lru-map.js +52 -0
  71. package/dist/src/utility/lru-map.js.map +1 -0
  72. package/package.json +15 -8
  73. package/src/btree/btree.ts +71 -50
  74. package/src/cluster/structs.ts +11 -0
  75. package/src/collection/collection.ts +44 -0
  76. package/src/index.ts +1 -0
  77. package/src/log/log.ts +1 -1
  78. package/src/logger.ts +10 -0
  79. package/src/transaction/coordinator.ts +244 -57
  80. package/src/transaction/index.ts +4 -2
  81. package/src/transaction/session.ts +38 -14
  82. package/src/transaction/transaction.ts +23 -10
  83. package/src/transaction/validator.ts +34 -7
  84. package/src/transactor/network-transactor.ts +94 -13
  85. package/src/transactor/transactor-source.ts +28 -9
  86. package/src/transform/atomic-proxy.ts +49 -0
  87. package/src/transform/cache-source.ts +18 -4
  88. package/src/transform/index.ts +1 -0
  89. package/src/utility/batch-coordinator.ts +9 -1
  90. package/src/utility/hash-string.ts +14 -17
  91. package/src/utility/lru-map.ts +55 -0
  92. package/dist/index.min.js +0 -9
  93. package/dist/index.min.js.map +0 -7
@@ -12,7 +12,7 @@ import type { ExecutionResult, ITransactionEngine, TransactionStamp, CollectionA
12
12
  * - The Transaction is then committed through coordinator.commit() for PEND/COMMIT orchestration
13
13
  *
14
14
  * Usage:
15
- * const session = new TransactionSession(coordinator, engine);
15
+ * const session = await TransactionSession.create(coordinator, engine);
16
16
  * await session.execute('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
17
17
  * await session.execute('SELECT * FROM orders WHERE user_id = ?', [1]);
18
18
  * const result = await session.commit();
@@ -26,8 +26,12 @@ export declare class TransactionSession {
26
26
  private readonly stamp;
27
27
  private committed;
28
28
  private rolledBack;
29
- constructor(coordinator: TransactionCoordinator, engine: ITransactionEngine, peerId?: string, // TODO: Get from coordinator or config
30
- schemaHash?: string);
29
+ private constructor();
30
+ /**
31
+ * Create a new TransactionSession.
32
+ * Uses async factory because stamp creation requires SHA-256 hashing.
33
+ */
34
+ static create(coordinator: TransactionCoordinator, engine: ITransactionEngine, peerId?: string, schemaHash?: string, ttlMs?: number): Promise<TransactionSession>;
31
35
  /**
32
36
  * Execute a statement.
33
37
  *
@@ -49,11 +53,11 @@ export declare class TransactionSession {
49
53
  */
50
54
  commit(): Promise<ExecutionResult>;
51
55
  /**
52
- * Rollback the transaction (discard local state).
56
+ * Rollback the transaction (undo this session's applied actions).
53
57
  *
54
- * Note: Actions have already been applied to collections' trackers.
55
- * Rollback just prevents commit and clears session state.
56
- * Collections will discard tracker state when they sync or update.
58
+ * Delegates to coordinator.rollback(stampId) which restores collection
59
+ * trackers to the pre-session snapshot and replays any later sessions'
60
+ * actions to preserve their transforms.
57
61
  */
58
62
  rollback(): Promise<void>;
59
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAe,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG9H;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,kBAAkB;IAO7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;gBAGT,WAAW,EAAE,sBAAsB,EACnC,MAAM,EAAE,kBAAkB,EAC3C,MAAM,GAAE,MAAgB,EAAE,uCAAuC;IACjE,UAAU,GAAE,MAAW;IAWxB;;;;;;;;;OASG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2C9G;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAuBxC;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAc/B;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAI5B;;OAEG;IACH,aAAa,IAAI,SAAS,MAAM,EAAE;IAIlC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,OAAO;CAGvB"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAe,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG9H;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,kBAAkB;IAO7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO;IAQP;;;OAGG;WACU,MAAM,CAClB,WAAW,EAAE,sBAAsB,EACnC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,GAAE,MAAgB,EACxB,UAAU,GAAE,MAAW,EACvB,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC;IAW9B;;;;;;;;;OASG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2C9G;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAgCxC;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAe/B;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAI5B;;OAEG;IACH,aAAa,IAAI,SAAS,MAAM,EAAE;IAIlC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,OAAO;CAGvB"}
@@ -1,4 +1,4 @@
1
- import { createTransactionStamp, createTransactionId } from "./transaction.js";
1
+ import { createTransactionStamp, createTransactionId, isTransactionExpired } from "./transaction.js";
2
2
  /**
3
3
  * TransactionSession manages incremental transaction building.
4
4
  *
@@ -11,7 +11,7 @@ import { createTransactionStamp, createTransactionId } from "./transaction.js";
11
11
  * - The Transaction is then committed through coordinator.commit() for PEND/COMMIT orchestration
12
12
  *
13
13
  * Usage:
14
- * const session = new TransactionSession(coordinator, engine);
14
+ * const session = await TransactionSession.create(coordinator, engine);
15
15
  * await session.execute('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
16
16
  * await session.execute('SELECT * FROM orders WHERE user_id = ?', [1]);
17
17
  * const result = await session.commit();
@@ -25,14 +25,19 @@ export class TransactionSession {
25
25
  stamp;
26
26
  committed = false;
27
27
  rolledBack = false;
28
- constructor(coordinator, engine, peerId = 'local', // TODO: Get from coordinator or config
29
- schemaHash = '' // TODO: Get from engine
30
- ) {
28
+ constructor(coordinator, engine, stamp) {
31
29
  this.coordinator = coordinator;
32
30
  this.engine = engine;
33
- // Create stamp at BEGIN (stable throughout transaction)
34
- this.stamp = createTransactionStamp(peerId, Date.now(), schemaHash, 'unknown' // TODO: Get engine ID from engine
35
- );
31
+ this.stamp = stamp;
32
+ }
33
+ /**
34
+ * Create a new TransactionSession.
35
+ * Uses async factory because stamp creation requires SHA-256 hashing.
36
+ */
37
+ static async create(coordinator, engine, peerId = 'local', schemaHash = '', ttlMs) {
38
+ const stamp = await createTransactionStamp(peerId, Date.now(), schemaHash, 'unknown', // TODO: Get engine ID from engine
39
+ ttlMs);
40
+ return new TransactionSession(coordinator, engine, stamp);
36
41
  }
37
42
  /**
38
43
  * Execute a statement.
@@ -96,24 +101,31 @@ export class TransactionSession {
96
101
  if (this.rolledBack) {
97
102
  return { success: false, error: 'Transaction already rolled back' };
98
103
  }
104
+ if (isTransactionExpired(this.stamp)) {
105
+ return { success: false, error: `Transaction expired at ${this.stamp.expiration}` };
106
+ }
107
+ // Collect read dependencies from all participating collections
108
+ const reads = this.coordinator.getReadDependencies();
99
109
  // Create the complete transaction
100
110
  const transaction = {
101
111
  stamp: this.stamp,
102
112
  statements: this.statements,
103
- reads: [], // TODO: Track reads during statement execution
104
- id: createTransactionId(this.stamp.id, this.statements, [])
113
+ reads,
114
+ id: await createTransactionId(this.stamp.id, this.statements, reads)
105
115
  };
106
116
  // Commit through coordinator (which will orchestrate PEND/COMMIT)
107
117
  await this.coordinator.commit(transaction);
118
+ // Clear read dependencies after successful commit
119
+ this.coordinator.clearReadDependencies();
108
120
  this.committed = true;
109
121
  return { success: true };
110
122
  }
111
123
  /**
112
- * Rollback the transaction (discard local state).
124
+ * Rollback the transaction (undo this session's applied actions).
113
125
  *
114
- * Note: Actions have already been applied to collections' trackers.
115
- * Rollback just prevents commit and clears session state.
116
- * Collections will discard tracker state when they sync or update.
126
+ * Delegates to coordinator.rollback(stampId) which restores collection
127
+ * trackers to the pre-session snapshot and replays any later sessions'
128
+ * actions to preserve their transforms.
117
129
  */
118
130
  async rollback() {
119
131
  if (this.committed) {
@@ -124,6 +136,7 @@ export class TransactionSession {
124
136
  }
125
137
  // Rollback through coordinator
126
138
  await this.coordinator.rollback(this.stamp.id);
139
+ this.coordinator.clearReadDependencies();
127
140
  this.rolledBack = true;
128
141
  this.statements.length = 0;
129
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,8 @@ export type TransactionStamp = {
15
15
  schemaHash: string;
16
16
  /** Which engine (e.g., 'quereus@0.5.3', 'actions@1.0.0') */
17
17
  engineId: string;
18
+ /** Absolute ms epoch after which transaction is invalid */
19
+ expiration: number;
18
20
  /** Hash of the stamp fields (computed) - stable identifier throughout transaction */
19
21
  id: string;
20
22
  };
@@ -54,16 +56,20 @@ export type ReadDependency = {
54
56
  * Just the transaction ID - full transaction can be looked up separately if needed.
55
57
  */
56
58
  export type TransactionRef = string;
59
+ /** Default transaction time-to-live in milliseconds (30 seconds). */
60
+ export declare const DEFAULT_TRANSACTION_TTL_MS = 30000;
61
+ /** Check whether a transaction stamp has expired. */
62
+ export declare function isTransactionExpired(stamp: TransactionStamp): boolean;
57
63
  /**
58
64
  * Create a transaction stamp with computed id.
59
- * The id is a hash of the stamp fields.
65
+ * The id is a hash of the stamp fields (including expiration).
60
66
  */
61
- export declare function createTransactionStamp(peerId: string, timestamp: number, schemaHash: string, engineId: string): TransactionStamp;
67
+ export declare function createTransactionStamp(peerId: string, timestamp: number, schemaHash: string, engineId: string, ttlMs?: number): Promise<TransactionStamp>;
62
68
  /**
63
69
  * Create a transaction id from stamp id, statements, and reads.
64
70
  * This is the final transaction identity used in logs.
65
71
  */
66
- export declare function createTransactionId(stampId: string, statements: string[], reads: ReadDependency[]): string;
72
+ export declare function createTransactionId(stampId: string, statements: string[], reads: ReadDependency[]): Promise<string>;
67
73
  /**
68
74
  * Transaction engine interface.
69
75
  * Pluggable engines implement this to process transaction statements.
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,27 @@
1
1
  import { hashString } from "../utility/hash-string.js";
2
+ /** Default transaction time-to-live in milliseconds (30 seconds). */
3
+ export const DEFAULT_TRANSACTION_TTL_MS = 30_000;
4
+ /** Check whether a transaction stamp has expired. */
5
+ export function isTransactionExpired(stamp) {
6
+ return Date.now() > stamp.expiration;
7
+ }
2
8
  /**
3
9
  * Create a transaction stamp with computed id.
4
- * The id is a hash of the stamp fields.
10
+ * The id is a hash of the stamp fields (including expiration).
5
11
  */
6
- export function createTransactionStamp(peerId, timestamp, schemaHash, engineId) {
7
- const stampData = JSON.stringify({ peerId, timestamp, schemaHash, engineId });
8
- const id = `stamp:${hashString(stampData)}`;
9
- return { peerId, timestamp, schemaHash, engineId, id };
12
+ export async function createTransactionStamp(peerId, timestamp, schemaHash, engineId, ttlMs = DEFAULT_TRANSACTION_TTL_MS) {
13
+ const expiration = timestamp + ttlMs;
14
+ const stampData = JSON.stringify({ peerId, timestamp, schemaHash, engineId, expiration });
15
+ const id = `stamp:${await hashString(stampData)}`;
16
+ return { peerId, timestamp, schemaHash, engineId, expiration, id };
10
17
  }
11
18
  /**
12
19
  * Create a transaction id from stamp id, statements, and reads.
13
20
  * This is the final transaction identity used in logs.
14
21
  */
15
- export function createTransactionId(stampId, statements, reads) {
22
+ export async function createTransactionId(stampId, statements, reads) {
16
23
  const txData = JSON.stringify({ stampId, statements, reads });
17
- return `tx:${hashString(txData)}`;
24
+ return `tx:${await hashString(txData)}`;
18
25
  }
19
26
  /**
20
27
  * Helper to create an actions-based transaction statements array.
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAmEvD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACrC,MAAc,EACd,SAAiB,EACjB,UAAkB,EAClB,QAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9E,MAAM,EAAE,GAAG,SAAS,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAC5C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAClC,OAAe,EACf,UAAoB,EACpB,KAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,OAAO,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AACnC,CAAC;AAmDD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAgC;IACvE,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAsEvD,qEAAqE;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,qDAAqD;AACrD,MAAM,UAAU,oBAAoB,CAAC,KAAuB;IAC3D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,MAAc,EACd,SAAiB,EACjB,UAAkB,EAClB,QAAgB,EAChB,QAAgB,0BAA0B;IAE1C,MAAM,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1F,MAAM,EAAE,GAAG,SAAS,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAClD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACxC,OAAe,EACf,UAAoB,EACpB,KAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,OAAO,MAAM,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AACzC,CAAC;AAmDD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAgC;IACvE,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
@@ -1,5 +1,6 @@
1
- import type { CollectionId, Transforms } from '../index.js';
1
+ import type { BlockId, CollectionId, Transforms } from '../index.js';
2
2
  import type { Transaction, ITransactionEngine, ITransactionValidator, ValidationResult, CollectionActions } from './transaction.js';
3
+ import type { BlockActionState } from '../network/struct.js';
3
4
  /**
4
5
  * Engine registration for validation.
5
6
  */
@@ -21,6 +22,11 @@ export type ValidationCoordinatorFactory = () => {
21
22
  /** Dispose of the validation coordinator */
22
23
  dispose(): void;
23
24
  };
25
+ /**
26
+ * Provides current block state for read dependency validation.
27
+ * Returns the latest BlockActionState for a given block, or undefined if the block doesn't exist.
28
+ */
29
+ export type BlockStateProvider = (blockId: BlockId) => Promise<BlockActionState | undefined>;
24
30
  /**
25
31
  * Transaction validator implementation.
26
32
  *
@@ -30,7 +36,8 @@ export type ValidationCoordinatorFactory = () => {
30
36
  export declare class TransactionValidator implements ITransactionValidator {
31
37
  private readonly engines;
32
38
  private readonly createValidationCoordinator;
33
- constructor(engines: Map<string, EngineRegistration>, createValidationCoordinator: ValidationCoordinatorFactory);
39
+ private readonly blockStateProvider?;
40
+ constructor(engines: Map<string, EngineRegistration>, createValidationCoordinator: ValidationCoordinatorFactory, blockStateProvider?: BlockStateProvider | undefined);
34
41
  validate(transaction: Transaction, operationsHash: string): Promise<ValidationResult>;
35
42
  getSchemaHash(engineId: string): Promise<string | undefined>;
36
43
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,YAAY,EAA2B,UAAU,EAAe,MAAM,aAAa,CAAC;AAC3G,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAcpI;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,sCAAsC;IACtC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kDAAkD;IAClD,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG,MAAM;IAChD,qDAAqD;IACrD,YAAY,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,mDAAmD;IACnD,aAAa,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,OAAO,IAAI,IAAI,CAAC;CAChB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAEhE,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;gBAD3B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACxC,2BAA2B,EAAE,4BAA4B;IAGrE,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAiErF,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;OAGG;IACH,OAAO,CAAC,cAAc;CAItB"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAA2B,UAAU,EAAe,MAAM,aAAa,CAAC;AAC3G,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,iBAAiB,EAAkB,MAAM,kBAAkB,CAAC;AACpJ,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAe7D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,sCAAsC;IACtC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kDAAkD;IAClD,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG,MAAM;IAChD,qDAAqD;IACrD,YAAY,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,mDAAmD;IACnD,aAAa,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,OAAO,IAAI,IAAI,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;AAE7F;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAEhE,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBAFnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACxC,2BAA2B,EAAE,4BAA4B,EACzD,kBAAkB,CAAC,EAAE,kBAAkB,YAAA;IAGnD,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmFrF,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;OAGG;YACW,cAAc;CAI5B"}
@@ -1,3 +1,4 @@
1
+ import { isTransactionExpired } from './transaction.js';
1
2
  import { hashString } from '../utility/hash-string.js';
2
3
  /**
3
4
  * Transaction validator implementation.
@@ -8,12 +9,21 @@ import { hashString } from '../utility/hash-string.js';
8
9
  export class TransactionValidator {
9
10
  engines;
10
11
  createValidationCoordinator;
11
- constructor(engines, createValidationCoordinator) {
12
+ blockStateProvider;
13
+ constructor(engines, createValidationCoordinator, blockStateProvider) {
12
14
  this.engines = engines;
13
15
  this.createValidationCoordinator = createValidationCoordinator;
16
+ this.blockStateProvider = blockStateProvider;
14
17
  }
15
18
  async validate(transaction, operationsHash) {
16
19
  const { stamp, statements } = transaction;
20
+ // 0. Check expiration before any other work
21
+ if (isTransactionExpired(stamp)) {
22
+ return {
23
+ valid: false,
24
+ reason: `Transaction expired at ${stamp.expiration}`
25
+ };
26
+ }
17
27
  // 1. Verify engine exists
18
28
  const registration = this.engines.get(stamp.engineId);
19
29
  if (!registration) {
@@ -31,8 +41,18 @@ export class TransactionValidator {
31
41
  };
32
42
  }
33
43
  // 3. Verify read dependencies (optimistic concurrency)
34
- // TODO: Implement read dependency validation
35
- // For now, we skip this check - will be implemented with proper block versioning
44
+ if (this.blockStateProvider && transaction.reads.length > 0) {
45
+ for (const read of transaction.reads) {
46
+ const currentState = await this.blockStateProvider(read.blockId);
47
+ const currentRev = currentState?.latest?.rev ?? 0;
48
+ if (currentRev !== read.revision) {
49
+ return {
50
+ valid: false,
51
+ reason: `Stale read: block ${read.blockId} was at revision ${read.revision} but is now at ${currentRev}`
52
+ };
53
+ }
54
+ }
55
+ }
36
56
  // 4. Create isolated validation coordinator
37
57
  const validationCoordinator = this.createValidationCoordinator();
38
58
  try {
@@ -52,7 +72,7 @@ export class TransactionValidator {
52
72
  const transforms = validationCoordinator.getTransforms();
53
73
  const allOperations = this.collectOperations(transforms);
54
74
  // 8. Compute hash
55
- const computedHash = this.hashOperations(allOperations);
75
+ const computedHash = await this.hashOperations(allOperations);
56
76
  // 9. Compare with sender's hash
57
77
  if (computedHash !== operationsHash) {
58
78
  return {
@@ -85,9 +105,9 @@ export class TransactionValidator {
85
105
  * Compute hash of all operations.
86
106
  * Must match TransactionCoordinator.hashOperations for consistent validation.
87
107
  */
88
- hashOperations(operations) {
108
+ async hashOperations(operations) {
89
109
  const operationsData = JSON.stringify(operations);
90
- return `ops:${hashString(operationsData)}`;
110
+ return `ops:${await hashString(operationsData)}`;
91
111
  }
92
112
  }
93
113
  //# sourceMappingURL=validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGxD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAwCvD;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IAEd;IACA;IACA;IAHlB,YACkB,OAAwC,EACxC,2BAAyD,EACzD,kBAAuC;QAFvC,YAAO,GAAP,OAAO,CAAiC;QACxC,gCAA2B,GAA3B,2BAA2B,CAA8B;QACzD,uBAAkB,GAAlB,kBAAkB,CAAqB;IACtD,CAAC;IAEJ,KAAK,CAAC,QAAQ,CAAC,WAAwB,EAAE,cAAsB;QAC9D,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC;QAE1C,4CAA4C;QAC5C,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO;gBACN,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,0BAA0B,KAAK,CAAC,UAAU,EAAE;aACpD,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,OAAO;gBACN,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,mBAAmB,KAAK,CAAC,QAAQ,EAAE;aAC3C,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC;QAC3D,IAAI,eAAe,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;YAC1C,OAAO;gBACN,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,0BAA0B,eAAe,YAAY,KAAK,CAAC,UAAU,EAAE;aAC/E,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,IAAI,IAAI,CAAC,kBAAkB,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7D,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACjE,MAAM,UAAU,GAAG,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;gBAClD,IAAI,UAAU,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClC,OAAO;wBACN,KAAK,EAAE,KAAK;wBACZ,MAAM,EAAE,qBAAqB,IAAI,CAAC,OAAO,oBAAoB,IAAI,CAAC,QAAQ,kBAAkB,UAAU,EAAE;qBACxG,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;QAED,4CAA4C;QAC5C,MAAM,qBAAqB,GAAG,IAAI,CAAC,2BAA2B,EAAE,CAAC;QAEjE,IAAI,CAAC;YACJ,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC9D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACrB,OAAO;oBACN,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,wBAAwB,MAAM,CAAC,KAAK,EAAE;iBAC9C,CAAC;YACH,CAAC;YAED,iEAAiE;YACjE,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,MAAM,qBAAqB,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YACpE,CAAC;YAED,oDAAoD;YACpD,MAAM,UAAU,GAAG,qBAAqB,CAAC,aAAa,EAAE,CAAC;YACzD,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAEzD,kBAAkB;YAClB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAE9D,gCAAgC;YAChC,IAAI,YAAY,KAAK,cAAc,EAAE,CAAC;gBACrC,OAAO;oBACN,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,0BAA0B;oBAClC,YAAY;iBACZ,CAAC;YACH,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QACtC,CAAC;gBAAS,CAAC;YACV,qBAAqB,CAAC,OAAO,EAAE,CAAC;QACjC,CAAC;IACF,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB;QACnC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChD,OAAO,YAAY,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,UAAyC;QAClE,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACtE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAC3D,CAAC,EAAE,IAAI,EAAE,QAAiB,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAC3D;YACD,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,CAChE,CAAC,EAAE,IAAI,EAAE,QAAiB,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAChE;YACD,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAClC,CAAC,EAAE,IAAI,EAAE,QAAiB,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CACpD;SACD,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,cAAc,CAAC,UAAgC;QAC5D,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAClD,OAAO,OAAO,MAAM,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;IAClD,CAAC;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"network-transactor.d.ts","sourceRoot":"","sources":["../../../src/transactor/network-transactor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAA6B,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAc,aAAa,EAA+B,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAM5S,KAAK,qBAAqB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;CACnC,CAAA;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAGnD,IAAI,EAAE,qBAAqB;IAQtB,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC;IAkHnD,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAkC7D,uBAAuB;IA0C/B,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA4EnD,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAOtE,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAkC7C,WAAW;IAezB,0EAA0E;YAC5D,YAAY;IAiC1B,8FAA8F;YAChF,iBAAiB;IAe/B,oHAAoH;YACtG,WAAW;IAqBzB,OAAO,CAAC,mBAAmB;CAY3B;AAGD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAIlG"}
1
+ {"version":3,"file":"network-transactor.d.ts","sourceRoot":"","sources":["../../../src/transactor/network-transactor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAA6B,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAc,aAAa,EAA+B,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAS5S,KAAK,qBAAqB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;CACnC,CAAA;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAGnD,IAAI,EAAE,qBAAqB;IAQtB,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC;IAuHnD,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAkC7D,uBAAuB;IA+F/B,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA2FnD,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAOtE,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAqC7C,WAAW;IAezB,0EAA0E;YAC5D,YAAY;IAkC1B,8FAA8F;YAChF,iBAAiB;IAe/B,oHAAoH;YACtG,WAAW;IAqBzB,OAAO,CAAC,mBAAmB;CAY3B;AAGD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAIlG"}
@@ -3,6 +3,8 @@ import { transformForBlockId, groupBy, concatTransforms, concatTransform, transf
3
3
  import { blockIdToBytes } from "../utility/block-id-to-bytes.js";
4
4
  import { isRecordEmpty } from "../utility/is-record-empty.js";
5
5
  import { makeBatchesByPeer, incompleteBatches, everyBatch, allBatches, mergeBlocks, processBatches, createBatchesForPayload } from "../utility/batch-coordinator.js";
6
+ import { createLogger, verbose } from "../logger.js";
7
+ const log = createLogger('network-transactor');
6
8
  export class NetworkTransactor {
7
9
  keyNetwork;
8
10
  timeoutMs;
@@ -17,6 +19,8 @@ export class NetworkTransactor {
17
19
  async get(blockGets) {
18
20
  // Group by block id
19
21
  const distinctBlockIds = Array.from(new Set(blockGets.blockIds));
22
+ const t0 = Date.now();
23
+ log('get blockIds=%d', distinctBlockIds.length);
20
24
  const batches = await this.batchesForPayload(distinctBlockIds, distinctBlockIds, (gets, blockId, mergeWithGets) => [...(mergeWithGets ?? []), ...gets.filter(bid => bid === blockId)], []);
21
25
  const expiration = Date.now() + this.timeoutMs;
22
26
  let error;
@@ -44,6 +48,7 @@ export class NetworkTransactor {
44
48
  // This provides tolerance for different cluster member views
45
49
  const retryable = Array.from(allBatches(batches)).filter(b => !hasValidResponse(b) || !hasBlockInResponse(b));
46
50
  if (retryable.length > 0 && Date.now() < expiration) {
51
+ log('get:retry retryable=%d', retryable.length);
47
52
  try {
48
53
  const excludedByRoot = new Map();
49
54
  for (const b of retryable) {
@@ -81,6 +86,7 @@ export class NetworkTransactor {
81
86
  // Ensure we have at least one response per requested block id
82
87
  const missingIds = distinctBlockIds.filter(bid => !resultEntries.has(bid));
83
88
  if (missingIds.length > 0) {
89
+ log('get:missing blockIds=%o', missingIds);
84
90
  const details = this.formatBatchStatuses(batches, b => b.request?.isResponse ?? false, b => {
85
91
  const status = b.request == null ? 'no-response' : (b.request.isResponse ? 'response' : 'in-flight');
86
92
  return `${b.peerId.toString()}[block:${b.blockId}](${status})`;
@@ -89,6 +95,7 @@ export class NetworkTransactor {
89
95
  aggregate.cause = error;
90
96
  throw aggregate;
91
97
  }
98
+ log('get:done blockIds=%d ms=%d', distinctBlockIds.length, Date.now() - t0);
92
99
  return Object.fromEntries(resultEntries);
93
100
  }
94
101
  async getStatus(blockActions) {
@@ -122,27 +129,75 @@ export class NetworkTransactor {
122
129
  }));
123
130
  }
124
131
  async consolidateCoordinators(blockIds, transforms, transformForBlock) {
125
- const blockCoordinators = await Promise.all(blockIds.map(async (bid) => ({
132
+ // Use cluster intersections to minimize the number of coordinators.
133
+ // For each block, find its full cluster, then greedily assign blocks to
134
+ // peers that appear in the most clusters — reducing round trips when
135
+ // blocks share cluster members.
136
+ // Step 1: Get cluster peer sets for each block
137
+ const blockClusterPeerIds = new Map();
138
+ const fallbackBlocks = [];
139
+ await Promise.all(blockIds.map(async (bid) => {
140
+ try {
141
+ const clusterPeers = await this.keyNetwork.findCluster(await blockIdToBytes(bid));
142
+ blockClusterPeerIds.set(bid, new Set(Object.keys(clusterPeers)));
143
+ }
144
+ catch {
145
+ fallbackBlocks.push(bid);
146
+ }
147
+ }));
148
+ // Step 2: Build peer → blocks index (which blocks each peer can coordinate)
149
+ const peerBlocks = new Map();
150
+ for (const [blockId, peerIds] of blockClusterPeerIds) {
151
+ for (const peerId of peerIds) {
152
+ const blocks = peerBlocks.get(peerId) ?? [];
153
+ blocks.push(blockId);
154
+ peerBlocks.set(peerId, blocks);
155
+ }
156
+ }
157
+ // Step 3: Greedy set cover — assign blocks to peers covering the most uncovered blocks
158
+ const uncovered = new Set(blockClusterPeerIds.keys());
159
+ const assignments = new Map(); // peerIdStr → assigned blockIds
160
+ while (uncovered.size > 0) {
161
+ let bestPeer;
162
+ let bestCount = 0;
163
+ for (const [peerId, blocks] of peerBlocks) {
164
+ const coverCount = blocks.filter(bid => uncovered.has(bid)).length;
165
+ if (coverCount > bestCount) {
166
+ bestCount = coverCount;
167
+ bestPeer = peerId;
168
+ }
169
+ }
170
+ if (!bestPeer || bestCount === 0)
171
+ break;
172
+ const covered = peerBlocks.get(bestPeer).filter(bid => uncovered.has(bid));
173
+ assignments.set(bestPeer, covered);
174
+ for (const bid of covered)
175
+ uncovered.delete(bid);
176
+ }
177
+ // Step 4: Any remaining uncovered blocks fall back to findCoordinator
178
+ for (const bid of uncovered)
179
+ fallbackBlocks.push(bid);
180
+ const fallbackCoordinators = await Promise.all(fallbackBlocks.map(async (bid) => ({
126
181
  blockId: bid,
127
182
  coordinator: await this.keyNetwork.findCoordinator(await blockIdToBytes(bid), { excludedPeers: [] })
128
183
  })));
129
- const byCoordinator = new Map();
130
- for (const { blockId, coordinator } of blockCoordinators) {
184
+ for (const { blockId, coordinator } of fallbackCoordinators) {
131
185
  const key = coordinator.toString();
132
- const blocks = byCoordinator.get(key) ?? [];
133
- blocks.push(blockId);
134
- byCoordinator.set(key, blocks);
186
+ const existing = assignments.get(key) ?? [];
187
+ existing.push(blockId);
188
+ assignments.set(key, existing);
135
189
  }
190
+ // Step 5: Convert assignments to batches
136
191
  const batches = [];
137
- for (const [coordinatorStr, consolidatedBlocks] of byCoordinator) {
138
- const coordinator = blockCoordinators.find(bc => bc.coordinator.toString() === coordinatorStr).coordinator;
192
+ for (const [peerIdStr, consolidatedBlocks] of assignments) {
193
+ const peerId = peerIdFromString(peerIdStr);
139
194
  let batchTransforms = { inserts: {}, updates: {}, deletes: [] };
140
195
  for (const bid of consolidatedBlocks) {
141
196
  const blockTransforms = transformForBlock(transforms, bid, batchTransforms);
142
197
  batchTransforms = blockTransforms;
143
198
  }
144
199
  batches.push({
145
- peerId: coordinator,
200
+ peerId,
146
201
  payload: batchTransforms,
147
202
  blockId: consolidatedBlocks[0],
148
203
  coordinatingBlockIds: consolidatedBlocks,
@@ -152,6 +207,7 @@ export class NetworkTransactor {
152
207
  return batches;
153
208
  }
154
209
  async pend(blockAction) {
210
+ const t0 = Date.now();
155
211
  const transformForBlock = (payload, blockId, mergeWithPayload) => {
156
212
  const filteredTransform = transformForBlockId(payload, blockId);
157
213
  return mergeWithPayload
@@ -160,6 +216,17 @@ export class NetworkTransactor {
160
216
  };
161
217
  const blockIds = blockIdsForTransforms(blockAction.transforms);
162
218
  const batches = await this.consolidateCoordinators(blockIds, blockAction.transforms, transformForBlock);
219
+ log('pend actionId=%s blockIds=%d batches=%d', blockAction.actionId, blockIds.length, batches.length);
220
+ if (verbose) {
221
+ const batchSummary = batches.map(b => ({
222
+ peer: b.peerId.toString().substring(0, 12),
223
+ blocks: b.coordinatingBlockIds ?? [b.blockId],
224
+ inserts: Object.keys(b.payload.inserts ?? {}).length,
225
+ updates: Object.keys(b.payload.updates ?? {}).length,
226
+ deletes: b.payload.deletes?.length ?? 0
227
+ }));
228
+ log('pend:batches actionId=%s detail=%o', blockAction.actionId, batchSummary);
229
+ }
163
230
  const expiration = Date.now() + this.timeoutMs;
164
231
  let error;
165
232
  try {
@@ -196,9 +263,11 @@ export class NetworkTransactor {
196
263
  error = aggregate;
197
264
  }
198
265
  if (error) { // If any failures, cancel all pending actions as background microtask
266
+ log('pend:cancel actionId=%s', blockAction.actionId);
199
267
  void Promise.resolve().then(() => this.cancelBatch(batches, { blockIds, actionId: blockAction.actionId }));
200
268
  const stale = Array.from(allBatches(batches, b => b.request?.isResponse && !b.request.response.success));
201
269
  if (stale.length > 0) { // Any active stale failures should preempt reporting connection or other potential transient errors (we have information)
270
+ log('pend:stale actionId=%s staleCount=%d', blockAction.actionId, stale.length);
202
271
  return {
203
272
  success: false,
204
273
  missing: distinctBlockActionTransforms(stale.flatMap(b => b.request.response.missing).filter((x) => x !== undefined)),
@@ -208,6 +277,7 @@ export class NetworkTransactor {
208
277
  }
209
278
  // Collect replies back into result structure
210
279
  const completed = Array.from(allBatches(batches, b => b.request?.isResponse && b.request.response.success));
280
+ log('pend:done actionId=%s ms=%d batches=%d', blockAction.actionId, Date.now() - t0, batches.length);
211
281
  return {
212
282
  success: true,
213
283
  pending: completed.flatMap(b => b.request.response.pending),
@@ -215,6 +285,7 @@ export class NetworkTransactor {
215
285
  };
216
286
  }
217
287
  async cancel(actionRef) {
288
+ log('cancel actionId=%s blockIds=%d', actionRef.actionId, actionRef.blockIds.length);
218
289
  const batches = await this.batchesForPayload(actionRef.blockIds, actionRef.blockIds, mergeBlocks, []);
219
290
  const expiration = Date.now() + this.abortOrCancelTimeoutMs;
220
291
  await processBatches(batches, (batch) => this.getRepo(batch.peerId).cancel({ actionId: actionRef.actionId, blockIds: batch.payload }, { expiration }), batch => batch.payload, mergeBlocks, expiration, async (blockId, options) => this.keyNetwork.findCoordinator(await blockIdToBytes(blockId), options));
@@ -226,6 +297,8 @@ export class NetworkTransactor {
226
297
  return { nominees };
227
298
  }
228
299
  async commit(request) {
300
+ const t0 = Date.now();
301
+ log('commit actionId=%s rev=%d blockIds=%d', request.actionId, request.rev, request.blockIds.length);
229
302
  const allBlockIds = [...new Set([...request.blockIds, request.tailId])];
230
303
  // Commit the header block if provided and not already in blockIds
231
304
  if (request.headerId && !request.blockIds.includes(request.headerId)) {
@@ -253,6 +326,7 @@ export class NetworkTransactor {
253
326
  catch { /* ignore */ }
254
327
  }
255
328
  }
329
+ log('commit:done actionId=%s ms=%d', request.actionId, Date.now() - t0);
256
330
  return { success: true };
257
331
  }
258
332
  async commitBlock(blockId, blockIds, actionId, rev) {
@@ -273,6 +347,7 @@ export class NetworkTransactor {
273
347
  async commitBlocks({ blockIds, actionId, rev }) {
274
348
  const expiration = Date.now() + this.timeoutMs;
275
349
  const batches = await this.batchesForPayload(blockIds, blockIds, mergeBlocks, []);
350
+ log('commitBlocks actionId=%s rev=%d batches=%d', actionId, rev, batches.length);
276
351
  let error;
277
352
  try {
278
353
  await processBatches(batches, (batch) => this.getRepo(batch.peerId).commit({ actionId, blockIds: batch.payload, rev }, { expiration }), batch => batch.payload, mergeBlocks, expiration, async (blockId, options) => this.keyNetwork.findCoordinator(await blockIdToBytes(blockId), options));