Files
khadhroony-bot3/kb-pipeline/src/metadata_solana_program_preflight.rs
2026-08-06 06:12:54 +02:00

762 lines
33 KiB
Rust

// 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<crate::SolanaProgramMetadataStatefulReadResult>,
/// Explicit rent observations required by account growth operations.
pub rent_observations: std::vec::Vec<crate::SolanaProgramMetadataRentObservation>,
}
/// 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<kb_lib::MdPubkey>,
/// 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<std::string::String>,
}
/// Validates one Program Metadata plan against confirmed pre-execution state.
pub fn inspect_solana_program_metadata_preflight(
request: &crate::SolanaProgramMetadataPreflightRequest,
) -> kb_core::Result<crate::SolanaProgramMetadataPreflightReport> {
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::<std::vec::Vec<_>>();
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<bool> {
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<std::option::Option<u64>> {
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<u64> {
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<u64>,
) -> kb_core::Result<std::option::Option<u64>> {
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::<std::vec::Vec<_>>()
.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());
}
}