Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ MSP stop storing buckets for insolvent user task #366

Merged
merged 51 commits into from
Feb 27, 2025

Conversation

TDemeco
Copy link
Contributor

@TDemeco TDemeco commented Feb 12, 2025

This PR adds the MspStopStoringInsolventUserTask, which is the task in charge of deleting the currently stored buckets that belong to a user that has become insolvent. This task:

  • Reacts initially to the UserWithoutFunds event from the runtime. When it receives it, checks if any of the MSP's stored buckets belongs to the now-insolvent user, and then spawns concurrent tasks for each one that submit the required msp_stop_storing_bucket_for_insolvent_user extrinsic and waits for them to finish.
    • Once all tasks finish, if any failed we log what the error was. We could improve this in the future if needed.
    • Current limit is set to 20 concurrent tasks as a balance between parallelism and block space used. Can be changed in the future.
  • Reacts to the FinalisedMspStopStoringBucketInsolventUser (which is emitted when a block that contained a MspStopStoringBucketInsolventUser event gets finalised). When it receives it, it deletes the bucket from the forest storage and all that bucket's files from the file storage.

Pending TODOs:

  • Develop an integration test that comprehensively tests this flow. DONE

This change is made since a bucket status (such as its MSP) could change between the request was made and the new MSP responds, so it's not reliable
Added a check to make sure the payment stream between the MSP and the user exists when the user issues a new storage request. This is so we don't allow users that just stopped being insolvent to issue storage requests for buckets that the MSP hasn't deleted yet
@TDemeco TDemeco requested review from ffarall and links234 February 12, 2025 02:32
@TDemeco TDemeco marked this pull request as ready for review February 12, 2025 21:00
Base automatically changed from feat/stop-storing-bucket-insolvent-user to main February 14, 2025 20:43
Comment on lines 87 to 233
// Get the ID of this MSP in the MSP indexer table.
let msp = shc_indexer_db::models::Msp::get_by_onchain_msp_id(
&mut indexer_connection,
msp_on_chain_id.to_string(),
)
.await?;
let msp_id = msp.id;

// Get all the buckets this MSP is currently storing for the user.
let stored_buckets = shc_indexer_db::models::Bucket::get_by_msp_id_and_owner(
&mut indexer_connection,
msp_id,
insolvent_user.to_string(),
)
.await?;

// If we are, queue up a bucket deletion request for that user.
if !stored_buckets.is_empty() {
info!(target: LOG_TARGET, "Buckets found for user {:?}, queueing up bucket stop storing", insolvent_user);
// Queue a request to stop storing a bucket from the insolvent user.
self.storage_hub_handler
.blockchain
.queue_stop_storing_for_insolvent_user_request(
StopStoringForInsolventUserRequest::new(insolvent_user),
)
.await?;
}

Ok(())
}
}

impl<NT> EventHandler<MspStopStoringBucketInsolventUser> for MspStopStoringInsolventUserTask<NT>
where
NT: ShNodeType + 'static,
NT::FSH: MspForestStorageHandlerT,
{
async fn handle_event(
&mut self,
event: MspStopStoringBucketInsolventUser,
) -> anyhow::Result<()> {
info!(
target: LOG_TARGET,
"Processing MspStopStoringBucketInsolventUser for user {:?}",
event.owner
);

// Get the insolvent user from the event.
let insolvent_user = event.owner;

// Get the indexer database pool. If this MSP is not keeping an indexer, it won't be able to check if it has any buckets for
// this user and as such wont be able to stop storing them.
let indexer_db_pool = if let Some(indexer_db_pool) =
self.storage_hub_handler.indexer_db_pool.clone()
{
indexer_db_pool
} else {
error!(
target: LOG_TARGET,
"Indexer is disabled but a insolvent user event was received. Please provide a database URL (and enable indexer) for it to use this feature."
);

return Err(anyhow!("Indexer is disabled but a insolvent user event was received. Please provide a database URL (and enable indexer) for it to use this feature."));
};

// Try to connect to the indexer. It's needed to check if there are any buckets for
// this user that this MSP is storing.
let mut indexer_connection = indexer_db_pool.get().await?;

// Get the ID of this MSP in the MSP indexer table.
let msp = shc_indexer_db::models::Msp::get_by_onchain_msp_id(
&mut indexer_connection,
event.msp_id.to_string(),
)
.await?;
let msp_id = msp.id;

// Get all the buckets this MSP is currently storing for the user.
let stored_buckets = shc_indexer_db::models::Bucket::get_by_msp_id_and_owner(
&mut indexer_connection,
msp_id,
insolvent_user.to_string(),
)
.await?;

// If we are, queue up a bucket deletion request for that user.
if !stored_buckets.is_empty() {
info!(target: LOG_TARGET, "Buckets found for user {:?}, queueing up bucket stop storing", insolvent_user);
// Queue a request to stop storing a bucket from the insolvent user.
self.storage_hub_handler
.blockchain
.queue_stop_storing_for_insolvent_user_request(
StopStoringForInsolventUserRequest::new(insolvent_user),
)
.await?;
}

Ok(())
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repeated code. We could unify it. But most importantly, why not use a runtime API instead of the indexer for this?

By using the indexer:

  1. You require an MSP to be running an indexer, whereas before, it was only necessary if the MSP wanted to be able to accept moved buckets.
  2. You have the problem that the indexer follows the finalised state.

By using a runtime API:

  1. You can access the on-chain information of the latest block.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added runtime api in favor of indexer here f9ff4c7

Comment on lines 235 to 248
/// Handles the `ProcessStopStoringForInsolventUserRequest` event.
///
/// This event is triggered whenever a Forest write-lock can be acquired to process a `StopStoringForInsolventUserRequest`
/// after receiving either a `UserWithoutFunds` or `MspStopStoringBucketInsolventUser` event from the runtime.\
/// This task will:
/// - Stop storing the bucket for the insolvent user.
/// - Delete the bucket from the forest storage.
impl<NT> EventHandler<ProcessStopStoringForInsolventUserRequest>
for MspStopStoringInsolventUserTask<NT>
where
NT: ShNodeType + 'static,
NT::FSH: MspForestStorageHandlerT,
{
async fn handle_event(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that this task doesn't need to use the Forest write lock. It's not presenting any proof, just removing the whole bucket.

Sure, if you send this transaction together with confirmation of a storage request for this bucket, either the storage request will fail if it comes in second, or it will succeed if it comes in first. Either way the result is the same: the MSP will no longer be storing the bucket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do this in another PR since the ProcessStopStoringForInsolventUserRequestData event is being processed by both BSP and MSP nodes.

We would have to decouple this event so we can emit this under separate circumstances (i.e. emit the event without the need for a forest root write lock).

snowmead and others added 3 commits February 17, 2025 15:10
…g index db for buckets stored by insolvent users
…StopStoringForInsolventUserRequest` event processing from `MspStopStoringInsolventUserTask`
@TDemeco TDemeco requested review from ffarall and snowmead February 25, 2025 13:51
@TDemeco TDemeco merged commit 832b228 into main Feb 27, 2025
25 checks passed
@TDemeco TDemeco deleted the feat/msp-task-stop-storing-insolvent-user branch February 27, 2025 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants