diff --git a/test/suites/integration/msp/move-bucket.test.ts b/test/suites/integration/msp/move-bucket.test.ts index 0655bafc1..28ff4bbdd 100644 --- a/test/suites/integration/msp/move-bucket.test.ts +++ b/test/suites/integration/msp/move-bucket.test.ts @@ -303,7 +303,7 @@ describeMspNet( // Wait for the BSPs to volunteer and confirm storing the files so the storage requests get fulfilled. for (const fileKey of acceptedFileKeys) { - await userApi.wait.storageRequestFulfilled(fileKey); + await userApi.wait.storageRequestNotOnChain(fileKey); } }); diff --git a/test/util/bspNet/test-api.ts b/test/util/bspNet/test-api.ts index 9a2766075..a633e4c7b 100644 --- a/test/util/bspNet/test-api.ts +++ b/test/util/bspNet/test-api.ts @@ -311,9 +311,20 @@ export class BspNetTestApi implements AsyncDisposable { Waits.waitForAvailabilityToSendTx(this._api, address), /** - * Waits for a storage request to be fulfilled on-chain. + * Waits for a storage request to be removed from on-chain storage. + * This could happen because the storage request was fulfilled, it has expired or + * it has been rejected by the MSP. Either way, we only care that it's not on-chain anymore. * @param fileKey - File key of the storage request to wait for. - * @returns A promise that resolves when the storage request is fulfilled. + * @returns A promise that resolves when the storage request is not on-chain. + */ + storageRequestNotOnChain: (fileKey: H256 | string) => + Waits.waitForStorageRequestNotOnChain(this._api, fileKey), + + /** + * Waits for a storage request to be fulfilled by waiting and sealing blocks until + * the StorageRequestFulfilled event is detected. + * @param fileKey - File key of the storage request to wait for. + * @returns A promise that resolves when the storage request has been fulfilled. */ storageRequestFulfilled: (fileKey: H256 | string) => Waits.waitForStorageRequestFulfilled(this._api, fileKey) diff --git a/test/util/bspNet/waits.ts b/test/util/bspNet/waits.ts index 3c0ca5e39..be17cd622 100644 --- a/test/util/bspNet/waits.ts +++ b/test/util/bspNet/waits.ts @@ -4,7 +4,7 @@ import { sleep } from "../timer"; import { sealBlock } from "./block"; import assert from "node:assert"; import type { Address, H256 } from "@polkadot/types/interfaces"; -import type { WaitForTxOptions } from "./test-api"; +import type { EnrichedBspApi, WaitForTxOptions } from "./test-api"; /** * Generic function to wait for a transaction in the pool. @@ -503,7 +503,8 @@ export const waitForMspFileStorageComplete = async (api: ApiPromise, fileKey: H2 } }; -export const waitForStorageRequestFulfilled = async (api: ApiPromise, fileKey: H256 | string) => { +export const waitForStorageRequestNotOnChain = async (api: ApiPromise, fileKey: H256 | string) => { + // 10 iterations at 1 second per iteration = 10 seconds wait time const iterations = 10; const delay = 1000; for (let i = 0; i < iterations + 1; i++) { @@ -512,18 +513,72 @@ export const waitForStorageRequestFulfilled = async (api: ApiPromise, fileKey: H // Try to get the storage request from the chain const result = await api.query.fileSystem.storageRequests(fileKey); - // If the storage request wasn't found, it has been fulfilled. + // If the storage request wasn't found, it has been fulfilled/expired/rejected. if (result.isNone) { return; } // If it has been found, seal a new block and wait for the next iteration to check if - // it has been fulfilled. + // it has been fulfilled/expired/rejected. await sealBlock(api); } catch { assert( i !== iterations, - `Failed to detect storage request fulfilled after ${(i * delay) / 1000}s` + `Detected storage request in on-chain storage after ${(i * delay) / 1000}s` + ); + } + } +}; + +export const waitForStorageRequestFulfilled = async ( + api: EnrichedBspApi, + fileKey: H256 | string +) => { + // 10 iterations at 1 second per iteration = 10 seconds wait time + const iterations = 10; + const delay = 1000; + + // First check that the storage request exists in storage, since otherwise the StorageRequestFulfilled event + // will never be emitted. + const storageRequest = await api.query.fileSystem.storageRequests(fileKey); + assert( + storageRequest.isSome, + "Storage request not found in storage but `waitForStorageRequestFulfilled` was called" + ); + + for (let i = 0; i < iterations + 1; i++) { + try { + await sleep(delay); + // Check in the events of the last block to see if any StorageRequestFulfilled event were emitted and get them. + const storageRequestFulfilledEvents = await api.assert.eventMany( + "fileSystem", + "StorageRequestFulfilled" + ); + + // Check if any of the events are for the file key we are waiting for. + const storageRequestFulfilledEvent = storageRequestFulfilledEvents.find((event) => { + const storageRequestFulfilledEventData = + api.events.fileSystem.StorageRequestFulfilled.is(event.event) && event.event.data; + assert( + storageRequestFulfilledEventData, + "Event doesn't match type but eventMany should have filtered it out" + ); + storageRequestFulfilledEventData.fileKey.toString() === fileKey.toString(); + }); + + // If the event was found, check to make sure the storage request is not on-chain and return. + if (storageRequestFulfilledEvent) { + await waitForStorageRequestNotOnChain(api, fileKey); + return; + } + + // If the event was not found, seal a new block and wait for the next iteration to check if + // it has been emitted. + await sealBlock(api); + } catch { + assert( + i !== iterations, + `Storage request has not been fulfilled after ${(i * delay) / 1000}s` ); } }