v0.1.0-pre.035
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-pipeline/src/lib.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
@@ -16,6 +16,7 @@ mod solana_elgamal_registry_stateful;
|
||||
mod solana_token2022_correlation;
|
||||
mod solana_token2022_crypto_preflight;
|
||||
mod solana_token2022_devnet_scenarios;
|
||||
mod solana_token2022_execution_orchestration;
|
||||
mod solana_token2022_preflight;
|
||||
mod solana_token2022_proof_orchestration;
|
||||
mod solana_token2022_stateful;
|
||||
@@ -131,6 +132,20 @@ pub use self::solana_token2022_devnet_scenarios::DevnetSplValidationImplementati
|
||||
pub use self::solana_token2022_devnet_scenarios::DevnetSplValidationScenario;
|
||||
/// Returns the complete ordered Devnet scenario inventory.
|
||||
pub use self::solana_token2022_devnet_scenarios::devnet_spl_validation_scenarios;
|
||||
/// Maximum number of distinct signers accepted by one Token-2022 execution envelope.
|
||||
pub use self::solana_token2022_execution_orchestration::MAX_TOKEN2022_EXECUTION_SIGNERS;
|
||||
/// One explicit stateful postcondition retained after Token-2022 execution.
|
||||
pub use self::solana_token2022_execution_orchestration::Token2022ExecutionPostcondition;
|
||||
/// Result of one stateful postcondition after Token-2022 execution.
|
||||
pub use self::solana_token2022_execution_orchestration::Token2022ExecutionPostconditionStatus;
|
||||
/// Deterministic Token-2022 execution-readiness report.
|
||||
pub use self::solana_token2022_execution_orchestration::Token2022ExecutionReadinessReport;
|
||||
/// Complete deterministic Token-2022 execution-readiness request.
|
||||
pub use self::solana_token2022_execution_orchestration::Token2022ExecutionReadinessRequest;
|
||||
/// Aggregates Token-2022 postconditions without inventing success.
|
||||
pub use self::solana_token2022_execution_orchestration::summarize_token2022_postconditions;
|
||||
/// Validates the complete Token-2022 execution envelope before signing.
|
||||
pub use self::solana_token2022_execution_orchestration::validate_token2022_execution_readiness;
|
||||
/// Migrated MAX_TOKEN2022_PREFLIGHT_ACCOUNTS contract.
|
||||
pub use self::solana_token2022_preflight::MAX_TOKEN2022_PREFLIGHT_ACCOUNTS;
|
||||
/// Migrated MAX_TOKEN2022_PREFLIGHT_TOTAL_BYTES contract.
|
||||
|
||||
331
kb-pipeline/src/solana_token2022_execution_orchestration.rs
Normal file
331
kb-pipeline/src/solana_token2022_execution_orchestration.rs
Normal file
@@ -0,0 +1,331 @@
|
||||
// file: kb-pipeline/src/solana_token2022_execution_orchestration.rs
|
||||
// version: 1
|
||||
|
||||
//! Final Token-2022 execution-readiness and stateful postcondition contracts.
|
||||
|
||||
/// Maximum number of distinct transaction signers accepted by one Token-2022 execution envelope.
|
||||
pub const MAX_TOKEN2022_EXECUTION_SIGNERS: usize = 16;
|
||||
|
||||
/// Result of one stateful postcondition checked after a confirmed Token-2022 transaction.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Token2022ExecutionPostconditionStatus {
|
||||
/// The observed final state confirms the expected operation effect.
|
||||
Confirmed,
|
||||
/// The observed final state contradicts the expected operation effect.
|
||||
Contradicted,
|
||||
/// The operation has no supported stateful postcondition in the current contract.
|
||||
NotApplicable,
|
||||
}
|
||||
|
||||
/// One explicit stateful postcondition retained by the execution orchestrator.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Token2022ExecutionPostcondition {
|
||||
/// Stable semantic role such as `mint`, `source`, `destination`, or `registry`.
|
||||
pub role: std::string::String,
|
||||
/// Canonical account whose final state was inspected.
|
||||
pub account: kb_lib::MdPubkey,
|
||||
/// Explicit result of the postcondition.
|
||||
pub status: crate::Token2022ExecutionPostconditionStatus,
|
||||
/// Bounded diagnostic explaining the result without retaining complete account data.
|
||||
pub diagnostic: std::string::String,
|
||||
}
|
||||
|
||||
/// Complete deterministic request checked before Token-2022 transaction signing.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Token2022ExecutionReadinessRequest {
|
||||
/// Exact prepared executor plan.
|
||||
pub plan: kb_lib::ExApiPreparedExecutionPlan,
|
||||
/// Exact hash of the compiled Solana message.
|
||||
pub message_hash: std::string::String,
|
||||
/// Hash retained by the simulation evidence.
|
||||
pub simulated_message_hash: std::string::String,
|
||||
/// Whether the exact compiled message was simulated.
|
||||
pub simulated: bool,
|
||||
/// Whether the exact simulation succeeded.
|
||||
pub simulation_succeeded: bool,
|
||||
/// Stateful Token-2022 account preflight report.
|
||||
pub stateful_preflight: crate::Token2022PreflightReport,
|
||||
/// Cryptographic proof context-state preflight report.
|
||||
pub cryptographic_preflight: crate::Token2022CryptographicPreflightReport,
|
||||
/// Ordered proof orchestration report.
|
||||
pub proof_orchestration: crate::Token2022ProofOrchestrationReport,
|
||||
/// Public keys actually available to sign the transaction.
|
||||
pub resolved_signers: std::vec::Vec<kb_lib::MdPubkey>,
|
||||
/// Whether submission was explicitly requested.
|
||||
pub submit: bool,
|
||||
/// Whether submission received explicit operator confirmation.
|
||||
pub operator_confirmed: bool,
|
||||
}
|
||||
|
||||
/// Deterministic execution-readiness report produced before signing.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Token2022ExecutionReadinessReport {
|
||||
/// Stable operation code.
|
||||
pub operation_code: std::string::String,
|
||||
/// Exact compiled message hash bound to simulation.
|
||||
pub message_hash: std::string::String,
|
||||
/// Highest RPC context slot across stateful and cryptographic preflights.
|
||||
pub context_slot: u64,
|
||||
/// Ordered signer public keys required by the plan.
|
||||
pub required_signers: std::vec::Vec<kb_lib::MdPubkey>,
|
||||
/// Whether transaction signing and submission are authorized.
|
||||
pub send_authorized: bool,
|
||||
/// Ordered successful checks.
|
||||
pub checks: std::vec::Vec<std::string::String>,
|
||||
}
|
||||
|
||||
/// Validates the complete Token-2022 execution envelope before transaction signing.
|
||||
pub fn validate_token2022_execution_readiness(
|
||||
request: &crate::Token2022ExecutionReadinessRequest,
|
||||
) -> kb_core::Result<crate::Token2022ExecutionReadinessReport> {
|
||||
if request.plan.operation_code.trim().is_empty() {
|
||||
return std::result::Result::Err(kb_core::Error::config(
|
||||
"Token-2022 execution plan operation_code must not be empty",
|
||||
));
|
||||
}
|
||||
if request.plan.operation_code != request.proof_orchestration.operation_code {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_operation_mismatch",
|
||||
"Token-2022 plan and proof orchestration operation codes must match",
|
||||
));
|
||||
}
|
||||
if request.message_hash.trim().is_empty()
|
||||
|| request.simulated_message_hash.trim().is_empty()
|
||||
|| request.message_hash != request.simulated_message_hash
|
||||
{
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_simulation_message_mismatch",
|
||||
"Token-2022 simulation must be bound to the exact compiled message hash",
|
||||
));
|
||||
}
|
||||
if !request.simulated || !request.simulation_succeeded {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_simulation_required",
|
||||
"Token-2022 execution requires one successful exact-message simulation",
|
||||
));
|
||||
}
|
||||
if !request.proof_orchestration.simulation_required {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_proof_policy_mismatch",
|
||||
"Token-2022 proof orchestration must require simulation",
|
||||
));
|
||||
}
|
||||
if request.stateful_preflight.commitment != "confirmed"
|
||||
|| request.cryptographic_preflight.commitment != "confirmed"
|
||||
{
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_preflight_commitment_mismatch",
|
||||
"Token-2022 stateful and cryptographic preflights must use confirmed commitment",
|
||||
));
|
||||
}
|
||||
let required_signers = match validate_signers(
|
||||
request.plan.required_signers.as_slice(),
|
||||
request.resolved_signers.as_slice(),
|
||||
) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
if request.submit && !request.operator_confirmed {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_confirmation_required",
|
||||
"Token-2022 submission requires explicit operator confirmation",
|
||||
));
|
||||
}
|
||||
if request.submit && !request.proof_orchestration.send_authorized {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_proof_send_not_authorized",
|
||||
"Token-2022 proof orchestration did not authorize submission",
|
||||
));
|
||||
}
|
||||
if request.submit && request.plan.policy.dry_run {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_dry_run_blocks_submission",
|
||||
"Token-2022 plan remains dry-run and cannot be submitted",
|
||||
));
|
||||
}
|
||||
let context_slot = request
|
||||
.stateful_preflight
|
||||
.context_slot
|
||||
.max(request.cryptographic_preflight.context_slot);
|
||||
return std::result::Result::Ok(crate::Token2022ExecutionReadinessReport {
|
||||
operation_code: request.plan.operation_code.clone(),
|
||||
message_hash: request.message_hash.clone(),
|
||||
context_slot,
|
||||
required_signers,
|
||||
send_authorized: request.submit
|
||||
&& request.operator_confirmed
|
||||
&& request.proof_orchestration.send_authorized
|
||||
&& !request.plan.policy.dry_run,
|
||||
checks: vec![
|
||||
"operation_matches_proof_orchestration".to_string(),
|
||||
"simulation_bound_to_exact_message".to_string(),
|
||||
"confirmed_stateful_preflight".to_string(),
|
||||
"confirmed_cryptographic_preflight".to_string(),
|
||||
"all_required_signers_resolved".to_string(),
|
||||
"submission_policy_consistent".to_string(),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/// Aggregates explicit postconditions without converting unsupported checks into success.
|
||||
pub fn summarize_token2022_postconditions(
|
||||
postconditions: &[crate::Token2022ExecutionPostcondition],
|
||||
) -> crate::Token2022ExecutionPostconditionStatus {
|
||||
if postconditions.iter().any(|item| {
|
||||
return item.status == crate::Token2022ExecutionPostconditionStatus::Contradicted;
|
||||
}) {
|
||||
return crate::Token2022ExecutionPostconditionStatus::Contradicted;
|
||||
}
|
||||
if postconditions.iter().any(|item| {
|
||||
return item.status == crate::Token2022ExecutionPostconditionStatus::Confirmed;
|
||||
}) {
|
||||
return crate::Token2022ExecutionPostconditionStatus::Confirmed;
|
||||
}
|
||||
return crate::Token2022ExecutionPostconditionStatus::NotApplicable;
|
||||
}
|
||||
|
||||
fn validate_signers(
|
||||
required: &[kb_lib::ExApiRequiredSigner],
|
||||
resolved: &[kb_lib::MdPubkey],
|
||||
) -> kb_core::Result<std::vec::Vec<kb_lib::MdPubkey>> {
|
||||
if required.len() > crate::MAX_TOKEN2022_EXECUTION_SIGNERS
|
||||
|| resolved.len() > crate::MAX_TOKEN2022_EXECUTION_SIGNERS
|
||||
{
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_signer_limit_exceeded",
|
||||
format!(
|
||||
"Token-2022 execution accepts at most {} signers",
|
||||
crate::MAX_TOKEN2022_EXECUTION_SIGNERS
|
||||
),
|
||||
));
|
||||
}
|
||||
let mut required_unique =
|
||||
std::collections::BTreeMap::<std::string::String, kb_lib::MdPubkey>::new();
|
||||
for signer in required {
|
||||
required_unique
|
||||
.entry(signer.pubkey.0.clone())
|
||||
.or_insert_with(|| return signer.pubkey.clone());
|
||||
}
|
||||
let resolved_set = resolved
|
||||
.iter()
|
||||
.map(|signer| return signer.0.clone())
|
||||
.collect::<std::collections::BTreeSet<std::string::String>>();
|
||||
for signer in required_unique.values() {
|
||||
if !resolved_set.contains(signer.0.as_str()) {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"token2022_execution_signer_unresolved",
|
||||
format!("Token-2022 required signer {} is unresolved", signer.0),
|
||||
));
|
||||
}
|
||||
}
|
||||
return std::result::Result::Ok(required_unique.into_values().collect());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn pubkey(byte: u8) -> kb_lib::MdPubkey {
|
||||
return kb_lib::MdPubkey(bs58::encode([byte; 32]).into_string());
|
||||
}
|
||||
|
||||
fn request() -> crate::Token2022ExecutionReadinessRequest {
|
||||
let signer = pubkey(1);
|
||||
let policy = kb_lib::ExApiExecutionPolicy {
|
||||
dry_run: false,
|
||||
..std::default::Default::default()
|
||||
};
|
||||
let plan = kb_lib::ExApiPreparedExecutionPlan {
|
||||
executor_name: "kb-lib.executor.spl.token2022".to_string(),
|
||||
executor_version: "0.4.6".to_string(),
|
||||
intent_id: "intent".to_string(),
|
||||
operation_code: "spl_token_2022.confidential_transfer".to_string(),
|
||||
fee_payer: signer.clone(),
|
||||
instructions: vec![],
|
||||
required_signers: vec![kb_lib::ExApiRequiredSigner {
|
||||
pubkey: signer.clone(),
|
||||
role: "authority".to_string(),
|
||||
}],
|
||||
policy,
|
||||
requested_spend_lamports: 0,
|
||||
requested_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
};
|
||||
return crate::Token2022ExecutionReadinessRequest {
|
||||
plan,
|
||||
message_hash: "message-hash".to_string(),
|
||||
simulated_message_hash: "message-hash".to_string(),
|
||||
simulated: true,
|
||||
simulation_succeeded: true,
|
||||
stateful_preflight: crate::Token2022PreflightReport {
|
||||
commitment: "confirmed".to_string(),
|
||||
context_slot: 100,
|
||||
requested_data_bytes: 0,
|
||||
accounts: vec![],
|
||||
elgamal_registry_validated: false,
|
||||
},
|
||||
cryptographic_preflight: crate::Token2022CryptographicPreflightReport {
|
||||
commitment: "confirmed".to_string(),
|
||||
context_slot: 101,
|
||||
proof_contexts: vec![],
|
||||
},
|
||||
proof_orchestration: crate::Token2022ProofOrchestrationReport {
|
||||
operation_code: "spl_token_2022.confidential_transfer".to_string(),
|
||||
instructions_sysvar_required: true,
|
||||
inline_offsets: vec![1],
|
||||
context_requirements: vec![],
|
||||
simulation_required: true,
|
||||
send_authorized: true,
|
||||
checks: vec![],
|
||||
},
|
||||
resolved_signers: vec![signer],
|
||||
submit: true,
|
||||
operator_confirmed: true,
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_message_preflights_and_signers_authorize_submission() {
|
||||
let report = super::validate_token2022_execution_readiness(&request())
|
||||
.expect("complete Token-2022 readiness must succeed");
|
||||
assert!(report.send_authorized);
|
||||
assert_eq!(report.context_slot, 101);
|
||||
assert_eq!(report.required_signers.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn message_mismatch_missing_signer_and_dry_run_fail_closed() {
|
||||
let mut mismatched = request();
|
||||
mismatched.simulated_message_hash = "other".to_string();
|
||||
assert!(super::validate_token2022_execution_readiness(&mismatched).is_err());
|
||||
let mut missing = request();
|
||||
missing.resolved_signers.clear();
|
||||
assert!(super::validate_token2022_execution_readiness(&missing).is_err());
|
||||
let mut dry_run = request();
|
||||
dry_run.plan.policy.dry_run = true;
|
||||
assert!(super::validate_token2022_execution_readiness(&dry_run).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postcondition_summary_preserves_contradicted_and_not_applicable() {
|
||||
let account = pubkey(2);
|
||||
let not_applicable = crate::Token2022ExecutionPostcondition {
|
||||
role: "mint".to_string(),
|
||||
account: account.clone(),
|
||||
status: crate::Token2022ExecutionPostconditionStatus::NotApplicable,
|
||||
diagnostic: "no supported final-state assertion".to_string(),
|
||||
};
|
||||
assert_eq!(
|
||||
super::summarize_token2022_postconditions(&[not_applicable]),
|
||||
crate::Token2022ExecutionPostconditionStatus::NotApplicable
|
||||
);
|
||||
let contradicted = crate::Token2022ExecutionPostcondition {
|
||||
role: "source".to_string(),
|
||||
account,
|
||||
status: crate::Token2022ExecutionPostconditionStatus::Contradicted,
|
||||
diagnostic: "final extension inventory contradicts the expected effect".to_string(),
|
||||
};
|
||||
assert_eq!(
|
||||
super::summarize_token2022_postconditions(&[contradicted]),
|
||||
crate::Token2022ExecutionPostconditionStatus::Contradicted
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user