Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ magicblock-committor-program = { path = "./magicblock-committor-program", featur
magicblock-committor-service = { path = "./magicblock-committor-service" }
magicblock-config = { path = "./magicblock-config" }
magicblock-core = { path = "./magicblock-core" }
magicblock-delegation-program-api = { git = "https://github.com/magicblock-labs/delegation-program.git", tag = "v3.1.0" }
magicblock-delegation-program-api = { git = "https://github.com/magicblock-labs/delegation-program.git", rev = "6365d3c2e" }
magicblock-ledger = { path = "./magicblock-ledger" }
magicblock-magic-program-api = { path = "./magicblock-magic-program-api" }
magicblock-metrics = { path = "./magicblock-metrics" }
Expand Down
24 changes: 23 additions & 1 deletion magicblock-committor-service/src/intent_executor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use magicblock_rpc_client::{
utils::TransactionErrorMapper, MagicBlockRpcClientError,
};
use solana_instruction::error::InstructionError;
use solana_pubkey::Pubkey;
use solana_rpc_client_api::{
client_error::{Error as RpcClientError, ErrorKind as RpcClientErrorKind},
request::{RpcError, RpcRequest},
Expand Down Expand Up @@ -77,6 +78,23 @@ impl InternalError {
}
}

#[derive(thiserror::Error, Debug)]
pub enum FailedToRecoverError {
#[error("FailedToFetchAccountError: {0}")]
FailedToFetchAccountError(#[source] InternalError),
#[error("MissingCommitStateAccount for delegated account {0}")]
MissingCommitStateAccount(Pubkey),
}

impl FailedToRecoverError {
pub fn is_transient(&self) -> bool {
match self {
Self::FailedToFetchAccountError(err) => err.is_transient(),
Self::MissingCommitStateAccount(_) => false,
}
}
}

#[derive(thiserror::Error, Debug)]
pub enum IntentExecutorError {
#[error("EmptyIntentError")]
Expand Down Expand Up @@ -105,6 +123,8 @@ pub enum IntentExecutorError {
FailedCommitPreparationError(#[source] TransactionPreparatorError),
#[error("FailedFinalizePreparationError: {0}")]
FailedFinalizePreparationError(#[source] TransactionPreparatorError),
#[error("FailedToRecoverError: {0}")]
FailedToRecoverError(#[from] FailedToRecoverError),
}

impl IntentExecutorError {
Expand Down Expand Up @@ -149,6 +169,7 @@ impl IntentExecutorError {
Self::FailedToFinalizeError { .. }
| Self::FailedFinalizePreparationError(_) => false,
Self::FailedCommitPreparationError(err) => err.is_transient(),
Self::FailedToRecoverError(err) => err.is_transient(),
}
}

Expand All @@ -171,7 +192,8 @@ impl IntentExecutorError {
} => commit_signature.map(|el| (el, *finalize_signature)),
IntentExecutorError::EmptyIntentError
| IntentExecutorError::FailedToFitError
| IntentExecutorError::SignerError(_) => None,
| IntentExecutorError::SignerError(_)
| IntentExecutorError::FailedToRecoverError(_) => None,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ use magicblock_rpc_client::{
decide_rpc_error_flow, map_magicblock_client_error,
send_transaction_with_retries, SendErrorMapper, TransactionErrorMapper,
},
MagicBlockRpcClientError, MagicBlockSendTransactionConfig,
MagicBlockSendTransactionOutcome, MagicblockRpcClient,
MagicBlockRpcClientError, MagicBlockRpcClientResult,
MagicBlockSendTransactionConfig, MagicBlockSendTransactionOutcome,
MagicblockRpcClient,
};
use solana_account::Account;
use solana_keypair::Keypair;
use solana_message::VersionedMessage;
use solana_pubkey::Pubkey;
use solana_rpc_client_api::config::RpcTransactionConfig;
use solana_signature::Signature;
use solana_transaction::versioned::VersionedTransaction;
Expand Down Expand Up @@ -211,4 +214,11 @@ impl IntentExecutionClient {
_ => {}
}
}

pub(in crate::intent_executor) async fn get_account(
&self,
pubkey: &Pubkey,
) -> MagicBlockRpcClientResult<Option<Account>> {
self.rpc_client.get_account(pubkey).await
}
}
7 changes: 7 additions & 0 deletions magicblock-committor-service/src/intent_executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,12 @@ where
Err(IntentExecutorError::SignerError(_)) => {
Some(CommitStatus::Failed)
}
Err(IntentExecutorError::FailedToRecoverError(_)) => {
// Occurs while preparing a finalize retry, before any
// transaction is sent — same treatment as
// FailedFinalizePreparationError.
None
}
};

if let Some(update_status) = update_status {
Expand Down Expand Up @@ -685,6 +691,7 @@ mod tests {
fn test_requires_uniqueness_nonce_on_first_commit_only() {
let finalize = BaseTaskImpl::Finalize(FinalizeTask {
delegated_account: Pubkey::new_unique(),
state_size: 0,
});

assert!(requires_uniqueness_nonce(&[commit_task(1)]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ use crate::{
intent_execution_client::IntentExecutionClient,
task_info_fetcher::{CacheTaskInfoFetcher, TaskInfoFetcher},
utils::{
handle_actions_result, handle_commit_id_error,
handle_undelegation_error, prepare_and_execute_strategy,
fetch_finalize_state_size, handle_actions_result,
handle_commit_id_error, handle_undelegation_error,
prepare_and_execute_strategy,
},
IntentExecutionReport,
},
Expand Down Expand Up @@ -279,8 +280,15 @@ where
delegated_account: Pubkey,
transaction_preparator: &T,
) -> IntentExecutorResult<ControlFlow<(), TransactionStrategy>> {
let finalize_task: BaseTaskImpl =
FinalizeTask { delegated_account }.into();
// Fetch commit_state to size prealloca
let state_size =
fetch_finalize_state_size(&self.intent_client, delegated_account)
.await?;
let finalize_task: BaseTaskImpl = FinalizeTask {
delegated_account,
state_size,
}
.into();
prepare_and_execute_strategy(
&self.intent_client,
&self.authority,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ use crate::{
task_info_fetcher::{CacheTaskInfoFetcher, TaskInfoFetcher},
two_stage_executor::sealed::Sealed,
utils::{
handle_actions_result, handle_commit_id_error,
handle_undelegation_error, prepare_and_execute_strategy,
fetch_finalize_state_size, handle_actions_result,
handle_commit_id_error, handle_undelegation_error,
prepare_and_execute_strategy,
},
IntentExecutionReport,
},
Expand Down Expand Up @@ -300,8 +301,15 @@ where
delegated_account: Pubkey,
transaction_preparator: &T,
) -> IntentExecutorResult<ControlFlow<(), TransactionStrategy>> {
let finalize_task: BaseTaskImpl =
FinalizeTask { delegated_account }.into();
let state_size =
fetch_finalize_state_size(&self.intent_client, delegated_account)
.await?;

let finalize_task: BaseTaskImpl = FinalizeTask {
delegated_account,
state_size,
}
.into();
prepare_and_execute_strategy(
&self.intent_client,
&self.authority,
Expand Down
30 changes: 29 additions & 1 deletion magicblock-committor-service/src/intent_executor/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use tracing::info;

use crate::{
intent_executor::{
error::{IntentExecutorResult, TransactionStrategyExecutionError},
error::{
FailedToRecoverError, IntentExecutorResult,
TransactionStrategyExecutionError,
},
intent_execution_client::IntentExecutionClient,
single_stage_executor::SingleStageExecutor,
task_info_fetcher::{CacheTaskInfoFetcher, ResetType, TaskInfoFetcher},
Expand Down Expand Up @@ -433,6 +436,31 @@ where
}
}

/// Fetches the committed state's size for a delegated account whose commit
/// already landed (i.e. we're only retrying finalize), by reading its
/// commit_state PDA — which is always sized to the full committed state,
/// diff-delivered or not. Used to size finalize's account preallocation
/// correctly instead of guessing.
pub async fn fetch_finalize_state_size(
intent_client: &IntentExecutionClient,
delegated_account: Pubkey,
) -> Result<usize, FailedToRecoverError> {
let commit_state_pda =
dlp_api::pda::commit_state_pda_from_delegated_account(
&delegated_account,
);
let commit_state_account = intent_client
.get_account(&commit_state_pda)
.await
.map_err(|err| {
FailedToRecoverError::FailedToFetchAccountError(err.into())
})?
.ok_or(FailedToRecoverError::MissingCommitStateAccount(
delegated_account,
))?;
Ok(commit_state_account.data.len())
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl IntentSizeValidator {
fn finalize_task(account: &CommittedAccount) -> BaseTaskImpl {
FinalizeTask {
delegated_account: account.pubkey,
state_size: account.account.data.len(),
}
.into()
}
Expand All @@ -96,6 +97,7 @@ impl IntentSizeValidator {
rent_reimbursement: Pubkey::default(),
// We lack context here so let's assume worst case scenario
include_undelegation_request: true,
state_size: account.account.data.len(),
}
.into()
}
Expand Down
15 changes: 11 additions & 4 deletions magicblock-committor-service/src/tasks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::Pubkey;

pub mod commit_finalize_task;
pub mod commit_stage_task;
pub mod commit_task;
pub mod intent_size_validator;
pub mod preparation_task;
pub mod task_builder;
pub mod task_strategist;
pub mod utils;
Expand Down Expand Up @@ -174,6 +174,8 @@ pub struct UndelegateTask {
pub owner_program: Pubkey,
pub rent_reimbursement: Pubkey,
pub include_undelegation_request: bool,
/// Size of state to bFe processed
pub state_size: usize,
}

impl UndelegateTask {
Expand Down Expand Up @@ -205,6 +207,8 @@ impl From<UndelegateTask> for BaseTaskImpl {
#[derive(Clone, Debug)]
pub struct FinalizeTask {
pub delegated_account: Pubkey,
/// Size of state to be processed
pub state_size: usize,
}

impl FinalizeTask {
Expand Down Expand Up @@ -404,8 +408,8 @@ mod serialization_safety_test {

use crate::{
tasks::{
commit_stage_task::PreparationTask,
commit_task::{CommitDelivery, CommitTask},
preparation_task::BufferPreparationTask,
*,
},
test_utils,
Expand Down Expand Up @@ -452,6 +456,7 @@ mod serialization_safety_test {
// Test Finalize variant
let finalize_task: BaseTaskImpl = FinalizeTask {
delegated_account: Pubkey::new_unique(),
state_size: 101,
}
.into();
assert_serializable(&finalize_task.instruction(&validator));
Expand All @@ -462,6 +467,7 @@ mod serialization_safety_test {
owner_program: Pubkey::new_unique(),
rent_reimbursement: Pubkey::new_unique(),
include_undelegation_request: false,
state_size: 101,
}
.into();
assert_serializable(&undelegate_task.instruction(&validator));
Expand Down Expand Up @@ -522,6 +528,7 @@ mod serialization_safety_test {
owner_program: Pubkey::new_unique(),
rent_reimbursement: Pubkey::new_unique(),
include_undelegation_request: true,
state_size: 101,
}
.instruction(&Pubkey::new_unique());

Expand Down Expand Up @@ -568,7 +575,7 @@ mod serialization_safety_test {
make_buffer_commit_task(789, true, vec![0; 1024], 3000);

let Some(preparation_task) =
PreparationTask::from_commit(&mut commit_task)
BufferPreparationTask::from_commit(&mut commit_task)
else {
panic!("invalid preparation state on creation!");
};
Expand Down Expand Up @@ -597,7 +604,7 @@ fn test_close_buffer_limit() {
use tracing::info;

use crate::{
tasks::{commit_stage_task::CleanupTask, utils::TransactionUtils},
tasks::{preparation_task::CleanupTask, utils::TransactionUtils},
test_utils,
transactions::{
serialized_transaction_size, MAX_TRANSACTION_WIRE_SIZE,
Expand Down
Loading
Loading