// file: kb-pipeline/src/metadata_solana_program_preflight.rs // version: 2 //! Stateful preflight for Solana Program Metadata execution plans. /// Maximum number of bounded account snapshots accepted by one preflight. pub const MAX_SOLANA_PROGRAM_METADATA_PREFLIGHT_ACCOUNTS: usize = 16; /// One rent-exemption observation supplied by the caller for a growth operation. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SolanaProgramMetadataRentObservation { /// Account whose allocation or growth is being validated. pub account: kb_lib::MdPubkey, /// Target account-data size used for the rent query. pub target_space: u64, /// Lamports observed on the account before execution. pub observed_lamports: u64, /// Minimum lamports returned for `target_space`. pub required_lamports: u64, } impl crate::SolanaProgramMetadataRentObservation { /// Returns whether the account is sufficiently pre-funded. pub const fn is_satisfied(&self) -> bool { return self.observed_lamports >= self.required_lamports; } } /// Complete stateful preflight request for one prepared Program Metadata plan. #[derive(Clone, Debug, PartialEq)] pub struct SolanaProgramMetadataPreflightRequest { /// Exact typed intent used to build the plan. pub intent: kb_lib::ExMetadataSpmExecutionIntent, /// Exact prepared plan produced by `kb-lib`. pub plan: kb_lib::ExApiPreparedExecutionPlan, /// Confirmed account snapshots observed before simulation. pub before: std::vec::Vec, /// Explicit rent observations required by account growth operations. pub rent_observations: std::vec::Vec, } /// Deterministic Program Metadata preflight report. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct SolanaProgramMetadataPreflightReport { /// Stable operation code. pub operation_code: std::string::String, /// Primary account mutated by the instruction. pub target_account: kb_lib::MdPubkey, /// Highest confirmed context slot across supplied snapshots. pub context_slot: u64, /// Canonical accounts inspected by the preflight. pub inspected_accounts: std::vec::Vec, /// Safety decision applied before simulation. pub safety: kb_lib::ExSafetyEvaluation, /// Whether the on-chain program must validate an upgrade authority at runtime. pub runtime_authority_validation_required: bool, /// Ordered successful checks. pub checks: std::vec::Vec, } /// Validates one Program Metadata plan against confirmed pre-execution state. pub fn inspect_solana_program_metadata_preflight( request: &crate::SolanaProgramMetadataPreflightRequest, ) -> kb_core::Result { if request.before.len() > crate::MAX_SOLANA_PROGRAM_METADATA_PREFLIGHT_ACCOUNTS { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_account_limit_exceeded", "Solana Program Metadata preflight account limit exceeded", )); } let operation_code = request.intent.operation.operation_code(); if request.plan.operation_code != operation_code { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_operation_mismatch", "Program Metadata intent and plan operation codes must match", )); } if request.plan.instructions.len() != 1 { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_instruction_count_invalid", "Program Metadata plans must contain exactly one instruction", )); } let instruction = match request.plan.instructions.first() { std::option::Option::Some(value) => value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_instruction_missing", "Program Metadata plan instruction is missing", )); }, }; if instruction.program_id.0 != kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID || instruction.operation_code != operation_code || !kb_lib::EX_METADATA_SPM_SUPPORTED_OPERATION_CODES.contains(&operation_code) { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_instruction_contract_mismatch", "Program Metadata plan does not preserve the exact program and operation contract", )); } if request.intent.operation.requires_explicit_approval() && !request.intent.allow_destructive_operation { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_destructive_approval_required", "destructive Program Metadata execution requires explicit approval", )); } let safety = match kb_lib::ExSafetyChecker.evaluate_prepared_plan(&request.plan) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; if safety.decision == kb_lib::ExSafetyDecision::Deny { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_safety_denied", safety_violation_codes(safety.violations.as_slice()), )); } let mut snapshots = std::collections::BTreeMap::< std::string::String, &crate::SolanaProgramMetadataStatefulReadResult, >::new(); let mut context_slot = 0_u64; for snapshot in &request.before { if snapshot.commitment != "confirmed" { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_commitment_mismatch", "Program Metadata stateful snapshots must use confirmed commitment", )); } if snapshots.insert(snapshot.account.0.clone(), snapshot).is_some() { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_duplicate_account", format!("duplicate Program Metadata snapshot for {}", snapshot.account.0), )); } context_slot = context_slot.max(snapshot.context_slot); } let target_account = operation_target(&request.intent.operation).clone(); let target = match snapshots.get(target_account.0.as_str()) { std::option::Option::Some(value) => *value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_target_snapshot_missing", format!("missing preflight snapshot for {}", target_account.0), )); }, }; if let std::result::Result::Err(error) = validate_target_state(&request.intent.operation, target) { return std::result::Result::Err(error); } if let std::result::Result::Err(error) = validate_source_state(&request.intent.operation, &snapshots, target) { return std::result::Result::Err(error); } let runtime_authority_validation_required = match validate_authority_state(&request.intent.operation, target) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; if let std::result::Result::Err(error) = validate_rent_observations( &request.intent.operation, target, &snapshots, request.rent_observations.as_slice(), ) { return std::result::Result::Err(error); } let inspected_accounts = snapshots .values() .map(|value| return value.account.clone()) .collect::>(); tracing::debug!( target: crate::TRACING_TARGET, action = "inspect_solana_program_metadata_preflight", operation_code, target_account = %target_account.0, context_slot, inspected_account_count = inspected_accounts.len(), runtime_authority_validation_required, safety_decision = ?safety.decision, "validated Solana Program Metadata stateful preflight" ); return std::result::Result::Ok(crate::SolanaProgramMetadataPreflightReport { operation_code: operation_code.to_string(), target_account, context_slot, inspected_accounts, safety, runtime_authority_validation_required, checks: vec![ "program_id_exact".to_string(), "operation_code_exact".to_string(), "single_instruction_plan".to_string(), "confirmed_state_snapshots".to_string(), "target_state_compatible".to_string(), "source_state_compatible".to_string(), "authority_contract_checked".to_string(), "rent_prefunding_checked_when_required".to_string(), "common_safety_checked_before_simulation".to_string(), ], }); } fn operation_target(operation: &kb_lib::ExMetadataSpmOperation) -> &kb_lib::MdPubkey { return match operation { kb_lib::ExMetadataSpmOperation::Write { buffer, .. } | kb_lib::ExMetadataSpmOperation::Allocate { buffer, .. } => buffer, kb_lib::ExMetadataSpmOperation::Initialize { metadata, .. } | kb_lib::ExMetadataSpmOperation::SetData { metadata, .. } | kb_lib::ExMetadataSpmOperation::SetImmutable { metadata, .. } => metadata, kb_lib::ExMetadataSpmOperation::SetAuthority { account, .. } | kb_lib::ExMetadataSpmOperation::Trim { account, .. } | kb_lib::ExMetadataSpmOperation::Close { account, .. } | kb_lib::ExMetadataSpmOperation::Extend { account, .. } => account, }; } fn validate_target_state( operation: &kb_lib::ExMetadataSpmOperation, target: &crate::SolanaProgramMetadataStatefulReadResult, ) -> kb_core::Result<()> { let valid = match operation { kb_lib::ExMetadataSpmOperation::Write { .. } => { matches!(&target.state, crate::SolanaProgramMetadataObservedAccountState::Buffer(_)) }, kb_lib::ExMetadataSpmOperation::Initialize { data, .. } => { if data.is_some() { is_prefunded_uninitialized(target) } else { matches!(&target.state, crate::SolanaProgramMetadataObservedAccountState::Buffer(_)) } }, kb_lib::ExMetadataSpmOperation::SetData { .. } | kb_lib::ExMetadataSpmOperation::SetImmutable { .. } => { matches!(&target.state, crate::SolanaProgramMetadataObservedAccountState::Metadata(_)) }, kb_lib::ExMetadataSpmOperation::Allocate { .. } => is_prefunded_uninitialized(target), kb_lib::ExMetadataSpmOperation::SetAuthority { .. } | kb_lib::ExMetadataSpmOperation::Trim { .. } | kb_lib::ExMetadataSpmOperation::Close { .. } | kb_lib::ExMetadataSpmOperation::Extend { .. } => matches!( &target.state, crate::SolanaProgramMetadataObservedAccountState::Buffer(_) | crate::SolanaProgramMetadataObservedAccountState::Metadata(_) ), }; if !valid { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_target_state_invalid", format!( "operation {} cannot use target state {}", operation.operation_code(), target.state.code() ), )); } return std::result::Result::Ok(()); } fn is_prefunded_uninitialized(target: &crate::SolanaProgramMetadataStatefulReadResult) -> bool { return match &target.state { crate::SolanaProgramMetadataObservedAccountState::Uninitialized { owner, lamports, space: _, } => { *lamports > 0 && (owner.0 == kb_program_ids::SYSTEM_PROGRAM_ID || owner.0 == kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID) }, _ => false, }; } fn validate_source_state( operation: &kb_lib::ExMetadataSpmOperation, snapshots: &std::collections::BTreeMap< std::string::String, &crate::SolanaProgramMetadataStatefulReadResult, >, target: &crate::SolanaProgramMetadataStatefulReadResult, ) -> kb_core::Result<()> { match operation { kb_lib::ExMetadataSpmOperation::Write { offset, source, .. } => { let target_buffer = match &target.state { crate::SolanaProgramMetadataObservedAccountState::Buffer(value) => value, _ => return std::result::Result::Ok(()), }; let source_length = match source { kb_lib::ExMetadataSpmWriteSource::Inline { data } => data.len(), kb_lib::ExMetadataSpmWriteSource::Buffer { source_buffer } => { let source_snapshot = match snapshots.get(source_buffer.0.as_str()) { std::option::Option::Some(value) => *value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_missing", format!("missing source Buffer snapshot for {}", source_buffer.0), )); }, }; match &source_snapshot.state { crate::SolanaProgramMetadataObservedAccountState::Buffer(value) => { value.data.len() }, _ => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_invalid", "Write source account must be an initialized Buffer", )); }, } }, }; let offset = match usize::try_from(*offset) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_write_offset_invalid", error.to_string(), )); }, }; if offset.saturating_add(source_length) > target_buffer.allocated_data_bytes { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_write_out_of_bounds", "Write source exceeds the allocated Buffer capacity", )); } }, kb_lib::ExMetadataSpmOperation::SetData { source: kb_lib::ExMetadataSpmSetDataSource::Buffer { buffer, .. }, .. } => { let source_snapshot = match snapshots.get(buffer.0.as_str()) { std::option::Option::Some(value) => *value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_missing", format!("missing source Buffer snapshot for {}", buffer.0), )); }, }; if !matches!( &source_snapshot.state, crate::SolanaProgramMetadataObservedAccountState::Buffer(_) ) { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_invalid", "SetData source account must be an initialized Buffer", )); } }, _ => {}, } return std::result::Result::Ok(()); } fn validate_authority_state( operation: &kb_lib::ExMetadataSpmOperation, target: &crate::SolanaProgramMetadataStatefulReadResult, ) -> kb_core::Result { let (authority, has_program_context) = match operation { kb_lib::ExMetadataSpmOperation::Write { authority: _, .. } => { return std::result::Result::Ok(false); }, kb_lib::ExMetadataSpmOperation::Initialize { canonical, .. } => { return std::result::Result::Ok(*canonical); }, kb_lib::ExMetadataSpmOperation::Allocate { seed, canonical, .. } => { return std::result::Result::Ok(seed.is_some() && *canonical); }, kb_lib::ExMetadataSpmOperation::SetAuthority { authority, program_context, .. } | kb_lib::ExMetadataSpmOperation::SetData { authority, program_context, .. } | kb_lib::ExMetadataSpmOperation::SetImmutable { authority, program_context, .. } | kb_lib::ExMetadataSpmOperation::Trim { authority, program_context, .. } | kb_lib::ExMetadataSpmOperation::Close { authority, program_context, .. } | kb_lib::ExMetadataSpmOperation::Extend { authority, program_context, .. } => { (authority, program_context.is_some()) }, }; let (current_authority, canonical) = match &target.state { crate::SolanaProgramMetadataObservedAccountState::Buffer(value) => { (value.authority.as_deref(), value.canonical) }, crate::SolanaProgramMetadataObservedAccountState::Metadata(value) => { (value.authority.as_deref(), value.canonical) }, _ => return std::result::Result::Ok(false), }; if current_authority == std::option::Option::Some(authority.0.as_str()) { return std::result::Result::Ok(false); } if canonical && has_program_context { return std::result::Result::Ok(true); } return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_authority_mismatch", "the supplied authority does not match account state and no canonical program context was provided", )); } fn validate_rent_observations( operation: &kb_lib::ExMetadataSpmOperation, target: &crate::SolanaProgramMetadataStatefulReadResult, snapshots: &std::collections::BTreeMap< std::string::String, &crate::SolanaProgramMetadataStatefulReadResult, >, observations: &[crate::SolanaProgramMetadataRentObservation], ) -> kb_core::Result<()> { let expected_space = match expected_rent_target_space(operation, target, snapshots) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let expected_space = match expected_space { std::option::Option::Some(value) => value, std::option::Option::None => return std::result::Result::Ok(()), }; let observation = match observations.iter().find(|value| return value.account == target.account) { std::option::Option::Some(value) => value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_rent_observation_missing", format!("missing rent observation for {}", target.account.0), )); }, }; let observed_lamports = match target.lamports { std::option::Option::Some(value) => value, std::option::Option::None => 0, }; if observation.target_space != expected_space || observation.observed_lamports != observed_lamports || !observation.is_satisfied() { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_rent_not_satisfied", format!( "account {} has {} lamports but requires {} for exact target space {}", observation.account.0, observation.observed_lamports, observation.required_lamports, expected_space ), )); } return std::result::Result::Ok(()); } fn expected_rent_target_space( operation: &kb_lib::ExMetadataSpmOperation, target: &crate::SolanaProgramMetadataStatefulReadResult, snapshots: &std::collections::BTreeMap< std::string::String, &crate::SolanaProgramMetadataStatefulReadResult, >, ) -> kb_core::Result> { let header = match u64::try_from(kb_lib::DC_METADATA_SPM_METADATA_HEADER_BYTES) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_header_size_overflow", error.to_string(), )); }, }; return match operation { kb_lib::ExMetadataSpmOperation::Initialize { data: std::option::Option::Some(data), .. } => add_metadata_header(header, metadata_input_wire_len(data)), kb_lib::ExMetadataSpmOperation::SetData { source: kb_lib::ExMetadataSpmSetDataSource::PreserveExisting, .. } => std::result::Result::Ok(std::option::Option::None), kb_lib::ExMetadataSpmOperation::SetData { source: kb_lib::ExMetadataSpmSetDataSource::Inline { data }, .. } => add_metadata_header(header, metadata_input_wire_len(data)), kb_lib::ExMetadataSpmOperation::SetData { source: kb_lib::ExMetadataSpmSetDataSource::Buffer { buffer, .. }, .. } => { let source = match snapshots.get(buffer.0.as_str()) { std::option::Option::Some(value) => *value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_missing", format!("missing source Buffer snapshot for {}", buffer.0), )); }, }; let length = match &source.state { crate::SolanaProgramMetadataObservedAccountState::Buffer(value) => { match u64::try_from(value.data.len()) { std::result::Result::Ok(length) => length, std::result::Result::Err(error) => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_length_overflow", error.to_string(), )); }, } }, _ => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_source_buffer_invalid", "SetData source account must be an initialized Buffer", )); }, }; return add_metadata_header(header, std::result::Result::Ok(length)); }, kb_lib::ExMetadataSpmOperation::Allocate { .. } => { let current = match target.space { std::option::Option::Some(value) => value, std::option::Option::None => 0, }; std::result::Result::Ok(std::option::Option::Some(current.max(header))) }, kb_lib::ExMetadataSpmOperation::Extend { length, .. } => { let current = match target.space { std::option::Option::Some(value) => value, std::option::Option::None => { return std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_target_space_missing", "Extend requires the current account space", )); }, }; return match current.checked_add(u64::from(*length)) { std::option::Option::Some(value) => { std::result::Result::Ok(std::option::Option::Some(value)) }, std::option::Option::None => std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_target_space_overflow", "Extend target space overflowed u64", )), }; }, _ => std::result::Result::Ok(std::option::Option::None), }; } fn metadata_input_wire_len(data: &kb_lib::ExMetadataSpmDataInput) -> kb_core::Result { let length = match data { kb_lib::ExMetadataSpmDataInput::Direct { bytes } => bytes.len(), kb_lib::ExMetadataSpmDataInput::Url { url } => url.len(), kb_lib::ExMetadataSpmDataInput::External { .. } => { kb_lib::DC_METADATA_SPM_EXTERNAL_DATA_BYTES }, }; return match u64::try_from(length) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(error) => std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_data_length_overflow", error.to_string(), )), }; } fn add_metadata_header( header: u64, data_length: kb_core::Result, ) -> kb_core::Result> { let data_length = match data_length { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return match header.checked_add(data_length) { std::option::Option::Some(value) => { std::result::Result::Ok(std::option::Option::Some(value)) }, std::option::Option::None => std::result::Result::Err(kb_core::Error::new( "metadata_solana_program_preflight_target_space_overflow", "Program Metadata target space overflowed u64", )), }; } fn safety_violation_codes(violations: &[kb_lib::ExSafetyViolation]) -> std::string::String { if violations.is_empty() { return "Program Metadata execution safety denied without a diagnostic".to_string(); } return violations .iter() .map(|value| return value.code.as_str()) .collect::>() .join(","); } #[cfg(test)] mod tests { fn pubkey(value: u8) -> kb_lib::MdPubkey { return kb_lib::MdPubkey(solana_pubkey::Pubkey::new_from_array([value; 32]).to_string()); } fn policy(authority: &kb_lib::MdPubkey) -> kb_lib::ExApiExecutionPolicy { return kb_lib::ExApiExecutionPolicy { cost_limit: kb_lib::ExApiExecutionCostLimit { max_spend_lamports: std::option::Option::Some(0), max_fee_lamports: std::option::Option::Some(20_000), max_compute_unit_price_micro_lamports: std::option::Option::None, }, authorized_signers: vec![authority.clone()], post_execution_validation: kb_lib::ExApiPostExecutionValidationPolicy { canonical_insert_required: true, core_extraction_required: true, decode_replay_required: true, materialization_required: true, }, ..kb_lib::ExApiExecutionPolicy::default() }; } fn buffer_read( account: kb_lib::MdPubkey, authority: kb_lib::MdPubkey, ) -> crate::SolanaProgramMetadataStatefulReadResult { return crate::SolanaProgramMetadataStatefulReadResult { commitment: "confirmed".to_string(), context_slot: 42, account: account.clone(), lamports: std::option::Option::Some(1_000), owner: std::option::Option::Some(kb_lib::MdProgramId( kb_program_ids::METADATA_SOLANA_PROGRAM_METADATA_PROGRAM_ID.to_string(), )), space: std::option::Option::Some(100), state: crate::SolanaProgramMetadataObservedAccountState::Buffer( kb_lib::DcMetadataSpmBufferAccountSnapshot { account: account.0, program: std::option::Option::None, authority: std::option::Option::Some(authority.0), canonical: false, seed: kb_lib::DcMetadataSpmSeed::default(), data: vec![0_u8; 4], allocated_data_bytes: 4, }, ), materialized_output: std::option::Option::None, }; } #[test] fn write_preflight_requires_buffer_capacity_and_common_safety() { let authority = pubkey(2); let buffer = pubkey(3); let intent = kb_lib::ExMetadataSpmExecutionIntent { intent_id: "spm-preflight-write".to_string(), fee_payer: authority.clone(), policy: policy(&authority), allow_destructive_operation: true, operation: kb_lib::ExMetadataSpmOperation::Write { buffer: buffer.clone(), authority: authority.clone(), offset: 2, source: kb_lib::ExMetadataSpmWriteSource::Inline { data: vec![8, 9] }, }, }; let plan = kb_lib::ExApiTypedInstructionExecutor::build_prepared_plan( &kb_lib::ExMetadataSolanaProgramMetadataExecutor, &intent, ); assert!(plan.is_ok()); let plan = match plan { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let report = crate::inspect_solana_program_metadata_preflight( &crate::SolanaProgramMetadataPreflightRequest { intent, plan, before: vec![buffer_read(buffer, authority)], rent_observations: vec![], }, ); assert!(report.is_ok()); if let std::result::Result::Ok(value) = report { assert_eq!(value.operation_code, kb_lib::EX_METADATA_SPM_WRITE_OPERATION); assert_eq!(value.safety.decision, kb_lib::ExSafetyDecision::Allow); } } #[test] fn allocate_requires_vacancy_and_explicit_rent_evidence() { let authority = pubkey(4); let buffer = authority.clone(); let intent = kb_lib::ExMetadataSpmExecutionIntent { intent_id: "spm-preflight-allocate".to_string(), fee_payer: authority.clone(), policy: policy(&authority), allow_destructive_operation: false, operation: kb_lib::ExMetadataSpmOperation::Allocate { buffer: buffer.clone(), authority: authority.clone(), seed: std::option::Option::None, program_context: std::option::Option::None, canonical: false, allocate_account: true, }, }; let plan = kb_lib::ExApiTypedInstructionExecutor::build_prepared_plan( &kb_lib::ExMetadataSolanaProgramMetadataExecutor, &intent, ); assert!(plan.is_ok()); let plan = match plan { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let before = crate::SolanaProgramMetadataStatefulReadResult { commitment: "confirmed".to_string(), context_slot: 9, account: buffer.clone(), lamports: std::option::Option::Some(1_000), owner: std::option::Option::Some(kb_lib::MdProgramId( kb_program_ids::SYSTEM_PROGRAM_ID.to_string(), )), space: std::option::Option::Some(0), state: crate::SolanaProgramMetadataObservedAccountState::Uninitialized { owner: kb_lib::MdProgramId(kb_program_ids::SYSTEM_PROGRAM_ID.to_string()), lamports: 1_000, space: 0, }, materialized_output: std::option::Option::None, }; let missing_rent = crate::inspect_solana_program_metadata_preflight( &crate::SolanaProgramMetadataPreflightRequest { intent: intent.clone(), plan: plan.clone(), before: vec![before.clone()], rent_observations: vec![], }, ); assert!(missing_rent.is_err()); let target_space = match u64::try_from(kb_lib::DC_METADATA_SPM_BUFFER_HEADER_BYTES) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let report = crate::inspect_solana_program_metadata_preflight( &crate::SolanaProgramMetadataPreflightRequest { intent, plan, before: vec![before], rent_observations: vec![crate::SolanaProgramMetadataRentObservation { account: buffer, target_space, observed_lamports: 1_000, required_lamports: 900, }], }, ); assert!(report.is_ok()); } }