|
| 1 | +diff --git a/dest/storage/capsule_store/capsule_store.js b/dest/storage/capsule_store/capsule_store.js |
| 2 | +index f455fc151d506562fbf20aa5b13b269a30c981b1..dccd521181ed58ccef3a23da2418f4f7648d671f 100644 |
| 3 | +--- a/dest/storage/capsule_store/capsule_store.js |
| 4 | ++++ b/dest/storage/capsule_store/capsule_store.js |
| 5 | +@@ -108,11 +108,16 @@ export class CapsuleStore { |
| 6 | + this.#setOnStage(jobId, dbSlotKey, Buffer.concat(capsule.map((value)=>value.toBuffer()))); |
| 7 | + } |
| 8 | + /** |
| 9 | +- * Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. |
| 10 | ++ * Returns data previously stored via `storeCapsule` in the per-contract non-volatile database. Wraps the DB read in |
| 11 | ++ * a transactionAsync so it enters the serial queue and never observes a stale IndexedDB transaction set by a |
| 12 | ++ * concurrent transactionAsync caller. |
| 13 | + * @param contractAddress - The contract address under which the data is scoped. |
| 14 | + * @param slot - The slot in the database to read. |
| 15 | + * @returns The stored data or `null` if no data is stored under the slot. |
| 16 | + */ async getCapsule(contractAddress, slot, jobId, scope) { |
| 17 | ++ return this.#store.transactionAsync(()=>this.#getCapsuleInternal(contractAddress, slot, jobId, scope)); |
| 18 | ++ } |
| 19 | ++ /** Same as getCapsule but without its own transaction — for use inside an existing transactionAsync. */ async #getCapsuleInternal(contractAddress, slot, jobId, scope) { |
| 20 | + const dataBuffer = await this.#getFromStage(jobId, dbSlotToKey(contractAddress, slot, scope)); |
| 21 | + if (!dataBuffer) { |
| 22 | + this.logger.trace(`Data not found for contract ${contractAddress.toString()} and slot ${slot.toString()}`); |
| 23 | +@@ -182,7 +187,7 @@ export class CapsuleStore { |
| 24 | + // and not using a transaction here would heavily impact performance. |
| 25 | + return this.#store.transactionAsync(async ()=>{ |
| 26 | + // Load current length, defaulting to 0 if not found |
| 27 | +- const lengthData = await this.getCapsule(contractAddress, baseSlot, jobId, scope); |
| 28 | ++ const lengthData = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope); |
| 29 | + const currentLength = lengthData ? lengthData[0].toNumber() : 0; |
| 30 | + // Store each capsule at consecutive slots after baseSlot + 1 + currentLength |
| 31 | + for(let i = 0; i < content.length; i++){ |
| 32 | +@@ -204,12 +209,12 @@ export class CapsuleStore { |
| 33 | + // of jobs: different calls running concurrently on the same contract may cause trouble. |
| 34 | + return this.#store.transactionAsync(async ()=>{ |
| 35 | + // Load length, defaulting to 0 if not found |
| 36 | +- const maybeLength = await this.getCapsule(contractAddress, baseSlot, jobId, scope); |
| 37 | ++ const maybeLength = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope); |
| 38 | + const length = maybeLength ? maybeLength[0].toBigInt() : 0n; |
| 39 | + const values = []; |
| 40 | + // Read each capsule at consecutive slots after baseSlot |
| 41 | + for(let i = 0; i < length; i++){ |
| 42 | +- const currentValue = await this.getCapsule(contractAddress, arraySlot(baseSlot, i), jobId, scope); |
| 43 | ++ const currentValue = await this.#getCapsuleInternal(contractAddress, arraySlot(baseSlot, i), jobId, scope); |
| 44 | + if (currentValue == undefined) { |
| 45 | + throw new Error(`Expected non-empty value at capsule array in base slot ${baseSlot} at index ${i} for contract ${contractAddress}`); |
| 46 | + } |
| 47 | +@@ -229,7 +234,7 @@ export class CapsuleStore { |
| 48 | + // of jobs: different calls running concurrently on the same contract may cause trouble. |
| 49 | + return this.#store.transactionAsync(async ()=>{ |
| 50 | + // Load current length, defaulting to 0 if not found |
| 51 | +- const maybeLength = await this.getCapsule(contractAddress, baseSlot, jobId, scope); |
| 52 | ++ const maybeLength = await this.#getCapsuleInternal(contractAddress, baseSlot, jobId, scope); |
| 53 | + const originalLength = maybeLength ? maybeLength[0].toNumber() : 0; |
| 54 | + // Set the new length |
| 55 | + this.setCapsule(contractAddress, baseSlot, [ |
0 commit comments