Skip to content

Commit

Permalink
fix: 🐛 try fix for fullnet payment stream test
Browse files Browse the repository at this point in the history
  • Loading branch information
TDemeco committed Dec 12, 2024
1 parent aa9fa71 commit 80db1de
Showing 1 changed file with 122 additions and 22 deletions.
144 changes: 122 additions & 22 deletions test/suites/integration/msp/debt-collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,38 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
const destination = ["test/whatsup.jpg", "test/adolphus.jpg", "test/smile.jpg"];
const bucketName = "nothingmuch-3";

// Get the value propositions from the MSP. It should have at least one
const valueProps = await userApi.call.storageProvidersApi.queryValuePropositionsForMsp(
userApi.shConsts.DUMMY_MSP_ID
);

// Get the ID of the first one. This is going to be used to access the price per giga-unit of data per tick
const valuePropId = valueProps[0].id;

// Create a bucket for the user in this MSP
const newBucketEventEvent = await userApi.createBucket(bucketName, valuePropId);
const newBucketEventDataBlob =
userApi.events.fileSystem.NewBucket.is(newBucketEventEvent) && newBucketEventEvent.data;
assert(newBucketEventDataBlob, "NewBucket event data does not match expected type");

// Check that the payment stream between the user and the MSP was created and has a rate equal
// to the rate for a zero-sized bucket
const maybePaymentStream = await userApi.query.paymentStreams.fixedRatePaymentStreams(
userApi.shConsts.DUMMY_MSP_ID,
userApi.shConsts.NODE_INFOS.user.AddressId
);
assert(maybePaymentStream.isSome, "Payment stream not found");
let paymentStream = maybePaymentStream.unwrap();
const zeroSizeBucketFixedRate = userApi.consts.providers.zeroSizeBucketFixedRate.toNumber();
strictEqual(
paymentStream.rate.toNumber(),
zeroSizeBucketFixedRate,
"Payment stream rate does not match the expected value"
);

// Get the bucket ID from the event
bucketId = newBucketEventDataBlob.bucketId;

// Load each file in storage and issue the storage requests
const txs = [];
for (let i = 0; i < source.length; i++) {
const { fingerprint, file_size, location } =
Expand All @@ -61,24 +81,27 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
)
);
}

await userApi.block.seal({ calls: txs, signer: shUser });

// Allow time for the MSP to receive and store the file from the user
await sleep(3000);

const events = await userApi.assert.eventMany("fileSystem", "NewStorageRequest");
// Allow time for the MSP to receive and store the files from the user
await sleep(5000);

const matchedEvents = events.filter((e) =>
// Check that the storage request submission events were emitted
const newStorageRequestEvents = await userApi.assert.eventMany(
"fileSystem",
"NewStorageRequest"
);
const matchedStorageRequestEvents = newStorageRequestEvents.filter((e) =>
userApi.events.fileSystem.NewStorageRequest.is(e.event)
);
assert(
matchedEvents.length === source.length,
matchedStorageRequestEvents.length === source.length,
`Expected ${source.length} NewStorageRequest events`
);

// For each issued storage request, check that the file is in the MSP's storage
const issuedFileKeys = [];
for (const e of matchedEvents) {
for (const e of matchedStorageRequestEvents) {
const newStorageRequestDataBlob =
userApi.events.fileSystem.NewStorageRequest.is(e.event) && e.event.data;

Expand All @@ -96,26 +119,31 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
issuedFileKeys.push(newStorageRequestDataBlob.fileKey);
}

// Seal block containing the MSP's transaction response to the storage request
// Seal block containing the MSP's transaction response to the first received storage request
await userApi.wait.mspResponseInTxPool();
await userApi.block.seal();

let mspAcceptedStorageRequestDataBlob: any = undefined;

const eventsRecorded = await userApi.query.system.events();
const mspAcceptedStorageRequestEvent = eventsRecorded.find(
(e) => e.event.section === "fileSystem" && e.event.method === "MspAcceptedStorageRequest"
// Check that there's only one `MspAcceptedStorageRequest` event
let mspAcceptedStorageRequestEvents = await userApi.assert.eventMany(
"fileSystem",
"MspAcceptedStorageRequest"
);
assert(
mspAcceptedStorageRequestEvents.length === 1,
"Expected a single MspAcceptedStorageRequest event"
);

// Get its file key
const mspAcceptedStorageRequestEvent = mspAcceptedStorageRequestEvents[0];
if (mspAcceptedStorageRequestEvent) {
mspAcceptedStorageRequestDataBlob =
userApi.events.fileSystem.MspAcceptedStorageRequest.is(
mspAcceptedStorageRequestEvent.event
) && mspAcceptedStorageRequestEvent.event.data;
}

const acceptedFileKey = mspAcceptedStorageRequestDataBlob.fileKey.toString();

assert(acceptedFileKey, "MspAcceptedStorageRequest event were found");

// There is only a single key being accepted since it is the first file key to be processed and there is nothing to batch.
Expand All @@ -127,10 +155,12 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
// Allow time for the MSP to update the local forest root
await sleep(3000);

// Get the root of the bucket now that the file has been stored
const localBucketRoot = await mspApi.rpc.storagehubclient.getForestRoot(
newBucketEventDataBlob.bucketId.toString()
);

// Ensure the `BucketRootChanged` event was emitted
const { event: bucketRootChangedEvent } = await userApi.assert.eventPresent(
"providers",
"BucketRootChanged"
Expand All @@ -145,22 +175,47 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
"Expected BucketRootChanged event but received event of different type"
);

// Ensure the new root of the bucket matches the one in the event
strictEqual(bucketRootChangedDataBlob.newRoot.toString(), localBucketRoot.toString());

// Ensure that the file has been stored in the MSP's forest, in the bucket's trie
const isFileInForest = await mspApi.rpc.storagehubclient.isFileInForest(
newBucketEventDataBlob.bucketId.toString(),
acceptedFileKey
);

assert(isFileInForest.isTrue, "File is not in forest");

// Check that the rate of the payment stream between the user and the MSP has been updated
// to reflect the new size of the bucket
paymentStream = (
await userApi.query.paymentStreams.fixedRatePaymentStreams(
DUMMY_MSP_ID,
userApi.shConsts.NODE_INFOS.user.AddressId
)
).unwrap();
const firstFileSize = (
await userApi.rpc.storagehubclient.getFileMetadata(bucketId, acceptedFileKey)
)
.unwrap()

Check failure on line 200 in test/suites/integration/msp/debt-collection.test.ts

View workflow job for this annotation

GitHub Actions / Run FullNet Tests (1)

MSP receives files from user after issued storage requests

[Error [ERR_TEST_FAILURE]: Option: unwrapping a None value] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: Option: unwrapping a None value at Type.unwrap (file:///home/runner/work/storage-hub/storage-hub/node_modules/.pnpm/@PolkaDot[email protected]/node_modules/@polkadot/types-codec/base/Option.js:210:19) at TestContext.<anonymous> (/home/runner/work/storage-hub/storage-hub/test/suites/integration/msp/debt-collection.test.ts:200:8) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Test.run (node:internal/test_runner/test:932:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) }

Check failure on line 200 in test/suites/integration/msp/debt-collection.test.ts

View workflow job for this annotation

GitHub Actions / Run FullNet Tests (1)

MSP receives files from user after issued storage requests

[Error [ERR_TEST_FAILURE]: Option: unwrapping a None value] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Error: Option: unwrapping a None value at Type.unwrap (file:///home/runner/work/storage-hub/storage-hub/node_modules/.pnpm/@PolkaDot[email protected]/node_modules/@polkadot/types-codec/base/Option.js:210:19) at TestContext.<anonymous> (/home/runner/work/storage-hub/storage-hub/test/suites/integration/msp/debt-collection.test.ts:200:8) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Test.run (node:internal/test_runner/test:932:9) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) }
.file_size.toNumber();
const unitsInGigaUnit = 1024 * 1024 * 1024;
let expectedPaymentStreamRate = Math.round(
(valueProps[0].value_prop.price_per_giga_unit_of_data_per_block.toNumber() * firstFileSize) /
unitsInGigaUnit +
zeroSizeBucketFixedRate
);
strictEqual(paymentStream.rate.toNumber(), expectedPaymentStreamRate);

// Seal block containing the MSP's transaction response to the storage request
await userApi.wait.mspResponseInTxPool();
await userApi.block.seal();

const fileKeys2: string[] = [];

const mspAcceptedStorageRequestEvents = await userApi.assert.eventMany(
// Since we gave enough time to the MSP to receive both files before processing the response for the
// first one, we should have two `MspAcceptedStorageRequest` events (because of the batching)
mspAcceptedStorageRequestEvents = await userApi.assert.eventMany(
"fileSystem",
"MspAcceptedStorageRequest"
);
Expand All @@ -178,10 +233,12 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
// Allow time for the MSP to update the local forest root
await sleep(3000);

// Get the root of the bucket now that the files have been stored
const localBucketRoot2 = await mspApi.rpc.storagehubclient.getForestRoot(
newBucketEventDataBlob.bucketId.toString()
);

// Ensure the `BucketRootChanged` event was emitted
const { event: bucketRootChangedEvent2 } = await userApi.assert.eventPresent(
"providers",
"BucketRootChanged"
Expand All @@ -196,32 +253,75 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
"Expected BucketRootChanged event but received event of different type"
);

// Ensure the new root of the bucket matches the one in the event
strictEqual(bucketRootChangedDataBlob2.newRoot.toString(), localBucketRoot2.toString());

// Ensure that the files have been stored in the MSP's forest, in the bucket's trie
for (const fileKey of fileKeys2) {
const isFileInForest = await mspApi.rpc.storagehubclient.isFileInForest(
newBucketEventDataBlob.bucketId.toString(),
fileKey
);
assert(isFileInForest.isTrue, "File is not in forest");
}

// Check that the rate of the payment stream between the user and the MSP has been updated
// to reflect the new size of the bucket
paymentStream = (
await userApi.query.paymentStreams.fixedRatePaymentStreams(
DUMMY_MSP_ID,
userApi.shConsts.NODE_INFOS.user.AddressId
)
).unwrap();
const secondFileSize = (
await userApi.rpc.storagehubclient.getFileMetadata(bucketId, fileKeys2[0])
)
.unwrap()
.file_size.toNumber();
const thirdFileSize = (
await userApi.rpc.storagehubclient.getFileMetadata(bucketId, fileKeys2[1])
)
.unwrap()
.file_size.toNumber();
const sumOfSizeOfFiles = firstFileSize + secondFileSize + thirdFileSize;
expectedPaymentStreamRate = Math.round(
(valueProps[0].value_prop.price_per_giga_unit_of_data_per_block.toNumber() *
sumOfSizeOfFiles) /
unitsInGigaUnit +
zeroSizeBucketFixedRate
);
strictEqual(paymentStream.rate.toNumber(), expectedPaymentStreamRate);
});

it("MSP is charging user", async () => {
// Get the current block
let currentBlock = await userApi.rpc.chain.getHeader();
let currentBlockNumber = currentBlock.number.toNumber();

const blocksToAdvance = MSP_CHARGING_PERIOD - (currentBlockNumber % MSP_CHARGING_PERIOD) + 1;
await userApi.block.skipTo(currentBlockNumber + blocksToAdvance - 1);
// We want to advance to the next time the MSP is going to try to charge the user.
const blocksToAdvance = MSP_CHARGING_PERIOD - (currentBlockNumber % MSP_CHARGING_PERIOD);
await userApi.block.skipTo(currentBlockNumber + blocksToAdvance);

// Wait for the MSP to try to charge the user and seal a block.
await sleep(2000);
await userApi.block.seal();

// Verify that the MSP charged the users after the notified.
await userApi.assert.eventPresent("paymentStreams", "PaymentStreamCharged");
// Verify that the MSP was able to charge the user after the notify period.
const firstPaymentStreamChargedEvent = await userApi.assert.eventPresent(
"paymentStreams",
"PaymentStreamCharged"
);
assert(
userApi.events.paymentStreams.PaymentStreamCharged.is(firstPaymentStreamChargedEvent.event)
);
assert(firstPaymentStreamChargedEvent.event.data.providerId.eq(DUMMY_MSP_ID));
assert(
firstPaymentStreamChargedEvent.event.data.userAccount.eq(
userApi.shConsts.NODE_INFOS.user.AddressId
)
);

// Advance many MSP charging periods, to charge again, but this time with a known number of
// Advance many MSP charging periods to charge again, but this time with a known number of
// blocks since last charged. That way, we can check for the exact amount charged.
// Since the MSP is going to charge each period, the last charge should be for one period.
currentBlock = await userApi.rpc.chain.getHeader();
Expand All @@ -237,7 +337,7 @@ describeMspNet("Single MSP collecting debt", ({ before, createMspApi, it, create
valueProps[0].value_prop.price_per_giga_unit_of_data_per_block.toNumber();
const unitsInGigaUnit = 1024 * 1024 * 1024;
const expectedRateOfPaymentStream =
Math.ceil((pricePerGigaUnitOfDataPerBlock * bucketSize) / unitsInGigaUnit) +
Math.round((pricePerGigaUnitOfDataPerBlock * bucketSize) / unitsInGigaUnit) +
userApi.consts.providers.zeroSizeBucketFixedRate.toNumber();
const paymentStream = (
await userApi.query.paymentStreams.fixedRatePaymentStreams(
Expand Down

0 comments on commit 80db1de

Please sign in to comment.