Skip to content

Commit 74f8508

Browse files
TDemecoffarall
authored andcommitted
chore: 🔊 update logs for MSP distributing (#555)
* feat: 🔊 add logs to MSP distribution * test: ✅ add an integration test for MSP distribution to BSPs * refactor: 🔊 improve logs * fix: 🔇 change info log to debug for less verbosity
1 parent b1187e5 commit 74f8508

File tree

4 files changed

+229
-8
lines changed

4 files changed

+229
-8
lines changed

client/blockchain-service/src/handler_msp.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,11 @@ where
583583
/// the in-memory `files_to_distribute` state to not spawn duplicate tasks or
584584
/// re-emit for already-confirmed BSPs.
585585
pub(crate) fn spawn_distribute_file_to_bsps_tasks(&mut self, block_hash: &Runtime::Hash) {
586+
debug!(target: LOG_TARGET, "Spawning distribute file to BSPs tasks");
587+
586588
// Only distribute files to BSPs when explicitly enabled via configuration.
587589
if !self.config.enable_msp_distribute_files {
588-
trace!(target: LOG_TARGET, "MSP file distribution disabled by configuration. Skipping distribution scan.");
590+
debug!(target: LOG_TARGET, "MSP file distribution disabled by configuration. Skipping distribution scan.");
589591
return;
590592
}
591593

@@ -625,7 +627,7 @@ where
625627
// Also keep only those for which this MSP node is listed as one of
626628
// the `user_peer_ids` of the storage request, meaning it is meant to
627629
// be a distributor of the file.
628-
let storage_requests_to_distribute =
630+
let mut storage_requests_to_distribute =
629631
pending_storage_requests_for_this_msp
630632
.iter()
631633
.filter(|(_, storage_request)| {
@@ -665,7 +667,13 @@ where
665667
});
666668

667669
msp_is_distributor
668-
});
670+
})
671+
.peekable();
672+
673+
if storage_requests_to_distribute.peek().is_none() {
674+
debug!(target: LOG_TARGET, "No storage requests to distribute for MSP [{:?}]", managed_msp_id);
675+
return;
676+
}
669677

670678
// Distribute the files to the BSPs.
671679
for storage_request in storage_requests_to_distribute {
@@ -697,6 +705,8 @@ where
697705
block_hash: &Runtime::Hash,
698706
file_key: &Runtime::Hash,
699707
) {
708+
debug!(target: LOG_TARGET, "Distributing file [{:?}] to BSPs", file_key);
709+
700710
let managed_msp = match &mut self.maybe_managed_provider {
701711
Some(ManagedProvider::Msp(msp_handler)) => msp_handler,
702712
_ => {

client/src/tasks/bsp_upload_file.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ where
449449
let is_allowed = self.is_allowed(&event).await?;
450450

451451
if !is_allowed {
452+
warn!(target: LOG_TARGET, "File with file key {:x} is in our exclude list. Skipping volunteer.", event.file_key);
452453
return Ok(());
453454
}
454455

client/src/tasks/msp_distribute_file.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,16 @@ where
7676
Runtime: StorageEnableRuntime,
7777
{
7878
async fn handle_event(&mut self, event: DistributeFileToBsp<Runtime>) -> anyhow::Result<()> {
79-
info!(
80-
target: LOG_TARGET,
81-
"Distributing file to BSP",
82-
);
83-
8479
let file_key = event.file_key;
8580
let bsp_id = event.bsp_id;
8681

82+
info!(
83+
target: LOG_TARGET,
84+
"Distributing file {:x} to BSP {:?}",
85+
file_key,
86+
bsp_id
87+
);
88+
8789
// Register that this task is distributing the file to the BSP.
8890
// This avoids a second instance of this task from being spawned.
8991
// This can fail if the BSP is already registered as distributing file.
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import assert, { strictEqual } from "node:assert";
2+
import { u8aToHex } from "@polkadot/util";
3+
import { decodeAddress } from "@polkadot/util-crypto";
4+
import { describeMspNet, type EnrichedBspApi, shUser, waitFor } from "../../../util";
5+
6+
await describeMspNet(
7+
"MSP distributes files to BSPs",
8+
({ before, createMsp1Api, createBspApi, createUserApi, it }) => {
9+
let userApi: EnrichedBspApi;
10+
let mspApi: EnrichedBspApi;
11+
let bspApi: EnrichedBspApi;
12+
13+
before(async () => {
14+
userApi = await createUserApi();
15+
bspApi = await createBspApi();
16+
const maybeMspApi = await createMsp1Api();
17+
assert(maybeMspApi, "MSP API not available");
18+
mspApi = maybeMspApi;
19+
});
20+
21+
it("Network launches and can be queried", async () => {
22+
const userNodePeerId = await userApi.rpc.system.localPeerId();
23+
strictEqual(userNodePeerId.toString(), userApi.shConsts.NODE_INFOS.user.expectedPeerId);
24+
25+
const mspNodePeerId = await mspApi.rpc.system.localPeerId();
26+
strictEqual(mspNodePeerId.toString(), userApi.shConsts.NODE_INFOS.msp1.expectedPeerId);
27+
28+
const bspNodePeerId = await bspApi.rpc.system.localPeerId();
29+
strictEqual(bspNodePeerId.toString(), userApi.shConsts.NODE_INFOS.bsp.expectedPeerId);
30+
});
31+
32+
it("MSP distributes file to BSP correctly", async () => {
33+
const source = "res/whatsup.jpg";
34+
const destination = "test/whatsup.jpg";
35+
const bucketName = "distribution-test-bucket";
36+
37+
// Pause the BSP so it cannot volunteer initially
38+
await userApi.docker.pauseContainer("storage-hub-sh-bsp-1");
39+
40+
// Create bucket and issue storage request
41+
const newBucketEvent = await userApi.createBucket(bucketName);
42+
const newBucketEventDataBlob =
43+
userApi.events.fileSystem.NewBucket.is(newBucketEvent) && newBucketEvent.data;
44+
45+
assert(newBucketEventDataBlob, "Event doesn't match Type");
46+
47+
const ownerHex = u8aToHex(decodeAddress(userApi.shConsts.NODE_INFOS.user.AddressId)).slice(2);
48+
const {
49+
file_metadata: { location, fingerprint, file_size }
50+
} = await userApi.rpc.storagehubclient.loadFileInStorage(
51+
source,
52+
destination,
53+
ownerHex,
54+
newBucketEventDataBlob.bucketId
55+
);
56+
57+
strictEqual(location.toHuman(), destination);
58+
strictEqual(fingerprint.toString(), userApi.shConsts.TEST_ARTEFACTS[source].fingerprint);
59+
strictEqual(file_size.toBigInt(), userApi.shConsts.TEST_ARTEFACTS[source].size);
60+
61+
// Issue storage request with both user and MSP peer IDs
62+
await userApi.block.seal({
63+
calls: [
64+
userApi.tx.fileSystem.issueStorageRequest(
65+
newBucketEventDataBlob.bucketId,
66+
destination,
67+
userApi.shConsts.TEST_ARTEFACTS[source].fingerprint,
68+
userApi.shConsts.TEST_ARTEFACTS[source].size,
69+
userApi.shConsts.DUMMY_MSP_ID,
70+
[
71+
userApi.shConsts.NODE_INFOS.user.expectedPeerId,
72+
userApi.shConsts.NODE_INFOS.msp1.expectedPeerId
73+
],
74+
{
75+
Basic: null
76+
}
77+
)
78+
],
79+
signer: shUser
80+
});
81+
82+
// Get the new storage request event
83+
const { event: newStorageRequestEvent } = await userApi.assert.eventPresent(
84+
"fileSystem",
85+
"NewStorageRequest"
86+
);
87+
88+
const newStorageRequestDataBlob =
89+
userApi.events.fileSystem.NewStorageRequest.is(newStorageRequestEvent) &&
90+
newStorageRequestEvent.data;
91+
92+
assert(
93+
newStorageRequestDataBlob,
94+
"NewStorageRequest event data does not match expected type"
95+
);
96+
97+
// And get the file key from it
98+
const fileKey = newStorageRequestDataBlob.fileKey.toString();
99+
100+
// Wait for MSP to download and accept the storage request
101+
await waitFor({
102+
lambda: async () =>
103+
(await mspApi.rpc.storagehubclient.isFileInFileStorage(fileKey)).isFileFound
104+
});
105+
106+
await userApi.wait.mspResponseInTxPool(1);
107+
await userApi.block.seal();
108+
109+
// Get the MSP accepted storage request event
110+
const { event: mspAcceptedEvent } = await userApi.assert.eventPresent(
111+
"fileSystem",
112+
"MspAcceptedStorageRequest"
113+
);
114+
115+
const mspAcceptedDataBlob =
116+
userApi.events.fileSystem.MspAcceptedStorageRequest.is(mspAcceptedEvent) &&
117+
mspAcceptedEvent.data;
118+
119+
assert(mspAcceptedDataBlob, "MspAcceptedStorageRequest event data does not match type");
120+
121+
// Ensure the file key matches the one we issued
122+
strictEqual(mspAcceptedDataBlob.fileKey.toString(), fileKey);
123+
124+
// Verify that the MSP has the file in its bucket forest
125+
await waitFor({
126+
lambda: async () =>
127+
(
128+
await mspApi.rpc.storagehubclient.isFileInForest(
129+
newBucketEventDataBlob.bucketId.toString(),
130+
fileKey
131+
)
132+
).isTrue
133+
});
134+
135+
// Delete the file from the user node's file storage
136+
// This ensures that the BSP can only receive the file from the MSP
137+
await userApi.rpc.storagehubclient.removeFilesFromFileStorage([fileKey]);
138+
139+
// Verify that the file was deleted from the user's file storage
140+
await waitFor({
141+
lambda: async () => {
142+
const result = await userApi.rpc.storagehubclient.isFileInFileStorage(fileKey);
143+
return result.isFileNotFound;
144+
}
145+
});
146+
147+
// Resume the BSP node so it can detect and volunteer for the storage request
148+
await userApi.docker.resumeContainer({ containerName: "storage-hub-sh-bsp-1" });
149+
150+
// Wait for BSP to catch up to chain tip
151+
await userApi.wait.nodeCatchUpToChainTip(bspApi);
152+
153+
// Wait for BSP to volunteer for the storage request
154+
await userApi.wait.bspVolunteerInTxPool(1);
155+
await userApi.block.seal();
156+
157+
const { event: bspVolunteerEvent } = await userApi.assert.eventPresent(
158+
"fileSystem",
159+
"AcceptedBspVolunteer"
160+
);
161+
162+
const bspVolunteerDataBlob =
163+
userApi.events.fileSystem.AcceptedBspVolunteer.is(bspVolunteerEvent) &&
164+
bspVolunteerEvent.data;
165+
166+
assert(bspVolunteerDataBlob, "AcceptedBspVolunteer event data does not match type");
167+
168+
// Ensure the fingerprint matches the one we issued
169+
strictEqual(
170+
bspVolunteerDataBlob.fingerprint.toString(),
171+
userApi.shConsts.TEST_ARTEFACTS[source].fingerprint
172+
);
173+
strictEqual(bspVolunteerDataBlob.bspId.toString(), userApi.shConsts.DUMMY_BSP_ID);
174+
175+
// Wait for BSP to confirm storing the file (this means the MSP distributed the file
176+
// as that's the only way the file could have gotten to the BSP)
177+
await userApi.wait.bspStored({ expectedExts: 1, timeoutMs: 12000, sealBlock: true });
178+
179+
// Get the BSP confirmed storing event
180+
const { event: bspConfirmedEvent } = await userApi.assert.eventPresent(
181+
"fileSystem",
182+
"BspConfirmedStoring"
183+
);
184+
185+
const bspConfirmedDataBlob =
186+
userApi.events.fileSystem.BspConfirmedStoring.is(bspConfirmedEvent) &&
187+
bspConfirmedEvent.data;
188+
189+
assert(bspConfirmedDataBlob, "BspConfirmedStoring event data does not match type");
190+
191+
// Ensure the file key matches the one we issued
192+
strictEqual(bspConfirmedDataBlob.confirmedFileKeys[0][0].toString(), fileKey);
193+
strictEqual(bspConfirmedDataBlob.bspId.toString(), userApi.shConsts.DUMMY_BSP_ID);
194+
195+
// Verify that the file is in the BSP's file storage
196+
const isFileInStorage = await bspApi.rpc.storagehubclient.isFileInFileStorage(fileKey);
197+
assert(isFileInStorage.isFileFound, "File is not in BSP file storage");
198+
199+
// Verify that the file is in the BSP's forest
200+
await waitFor({
201+
lambda: async () => {
202+
const isInForest = await bspApi.rpc.storagehubclient.isFileInForest(null, fileKey);
203+
return isInForest.isTrue;
204+
}
205+
});
206+
});
207+
}
208+
);

0 commit comments

Comments
 (0)