v0.4.8-pre.011

This commit is contained in:
2026-08-07 07:14:49 +02:00
parent 3167297283
commit dcc1d382d9
38 changed files with 1358 additions and 129 deletions

View File

@@ -1,5 +1,5 @@
// file: kb-pipeline/src/lib.rs
// version: 20
// version: 21
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
@@ -24,6 +24,7 @@ mod spl_elgamal_registry_stateful;
mod spl_token_2022_correlation;
mod spl_token_2022_crypto_preflight;
mod spl_token_2022_execution_orchestration;
mod spl_token_2022_metadata;
mod spl_token_2022_preflight;
mod spl_token_2022_proof_orchestration;
mod spl_token_2022_stateful;
@@ -251,6 +252,16 @@ pub use self::spl_token_2022_execution_orchestration::Token2022ExecutionReadines
pub use self::spl_token_2022_execution_orchestration::summarize_token_2022_postconditions;
/// Validates the complete Token-2022 execution envelope before signing.
pub use self::spl_token_2022_execution_orchestration::validate_token_2022_execution_readiness;
/// Maximum Token Metadata bytes accepted from Solana return data.
pub use self::spl_token_2022_metadata::MAX_TOKEN_2022_METADATA_EMIT_BYTES;
/// Bounded evidence extracted from one successful Token Metadata `Emit` simulation.
pub use self::spl_token_2022_metadata::Token2022MetadataEmitEvidence;
/// Checks the final embedded metadata authority against one authoritative snapshot.
pub use self::spl_token_2022_metadata::inspect_token_2022_metadata_authority_postcondition;
/// Extracts and validates Token Metadata return data from one exact simulation.
pub use self::spl_token_2022_metadata::inspect_token_2022_metadata_emit_simulation;
/// Validates one Token Metadata `Emit` range against Solana return-data bounds.
pub use self::spl_token_2022_metadata::validate_token_2022_metadata_emit_range;
/// Migrated MAX_TOKEN_2022_PREFLIGHT_ACCOUNTS contract.
pub use self::spl_token_2022_preflight::MAX_TOKEN_2022_PREFLIGHT_ACCOUNTS;
/// Migrated MAX_TOKEN_2022_PREFLIGHT_TOTAL_BYTES contract.

View File

@@ -0,0 +1,376 @@
// file: kb-pipeline/src/spl_token_2022_metadata.rs
// version: 3
//! Token-2022 Token Metadata return-data and authority postcondition contracts.
use base64::Engine; // rust-rules: trait-import
/// Maximum Token Metadata bytes accepted from Solana return data.
pub const MAX_TOKEN_2022_METADATA_EMIT_BYTES: usize = 1_024;
/// Bounded evidence extracted from one successful Token Metadata `Emit` simulation.
#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Token2022MetadataEmitEvidence {
/// Program that produced the return data.
pub program_id: std::string::String,
/// Optional requested range start.
pub start: std::option::Option<u64>,
/// Optional requested range end.
pub end: std::option::Option<u64>,
/// Decoded return-data bytes.
pub data: std::vec::Vec<u8>,
/// Exact complete Token Metadata projection, only for an un-ranged emit.
pub decoded_metadata: std::option::Option<serde_json::Value>,
}
/// Validates one Token Metadata `Emit` range against Solana return-data bounds.
pub fn validate_token_2022_metadata_emit_range(
start: std::option::Option<u64>,
end: std::option::Option<u64>,
) -> kb_core::Result<()> {
if let (std::option::Option::Some(start), std::option::Option::Some(end)) = (start, end) {
if start > end {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_range_invalid",
format!("Token Metadata Emit start {start} exceeds end {end}"),
));
}
if end - start > crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES as u64 {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_range_too_large",
format!(
"Token Metadata Emit range exceeds {} bytes",
crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES
),
));
}
}
if let (std::option::Option::None, std::option::Option::Some(end)) = (start, end) {
if end > crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES as u64 {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_range_too_large",
format!(
"Token Metadata Emit range from zero exceeds {} bytes",
crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES
),
));
}
}
if let (std::option::Option::Some(_), std::option::Option::None) = (start, end) {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_range_end_required",
"Token Metadata Emit with a start offset requires an explicit end to remain bounded",
));
}
return std::result::Result::Ok(());
}
/// Extracts and validates Token Metadata return data from one exact simulation.
pub fn inspect_token_2022_metadata_emit_simulation(
simulation: &kb_lib::ExApiExecutionSimulationResult,
start: std::option::Option<u64>,
end: std::option::Option<u64>,
) -> kb_core::Result<crate::Token2022MetadataEmitEvidence> {
match crate::validate_token_2022_metadata_emit_range(start, end) {
std::result::Result::Ok(()) => {},
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
if !simulation.simulated || !simulation.success {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_simulation_required",
"Token Metadata Emit evidence requires a successful simulation",
));
}
let return_data = match simulation.return_data.as_ref() {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_return_data_missing",
"Token Metadata Emit simulation did not return program data",
));
},
};
let program_id = match return_data.get("programId").and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_program_id_missing",
"Token Metadata Emit return data is missing programId",
));
},
};
if program_id != kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_program_id_mismatch",
format!("Token Metadata Emit return data came from {program_id}"),
));
}
let data = match return_data.get("data").and_then(serde_json::Value::as_array) {
std::option::Option::Some(value) if value.len() == 2 => value,
_ => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_data_invalid",
"Token Metadata Emit return data must be [payload, encoding]",
));
},
};
let payload = match data.first().and_then(|value| return value.as_str()) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_payload_invalid",
"Token Metadata Emit return payload must be a base64 string",
));
},
};
let encoding = match data.get(1).and_then(|value| return value.as_str()) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_encoding_invalid",
"Token Metadata Emit return data encoding is missing",
));
},
};
if encoding != "base64" {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_encoding_invalid",
"Token Metadata Emit return data encoding must be base64",
));
}
let decoded = match base64::engine::general_purpose::STANDARD.decode(payload) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_base64_invalid",
format!("Token Metadata Emit return payload is invalid base64: {error}"),
));
},
};
if decoded.len() > crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_data_too_large",
format!(
"Token Metadata Emit returned {} bytes, maximum is {}",
decoded.len(),
crate::MAX_TOKEN_2022_METADATA_EMIT_BYTES
),
));
}
let decoded_metadata = if start.is_none() && end.is_none() {
match kb_lib::decoder_spl_token_2022_parse_token_metadata_value(decoded.as_slice()) {
std::result::Result::Ok(value) => std::option::Option::Some(value),
std::result::Result::Err(error) => {
return std::result::Result::Err(kb_core::Error::new(
"token_2022_metadata_emit_payload_decode_failed",
error,
));
},
}
} else {
std::option::Option::None
};
return std::result::Result::Ok(crate::Token2022MetadataEmitEvidence {
program_id: program_id.to_string(),
start,
end,
data: decoded,
decoded_metadata,
});
}
/// Checks the final embedded metadata authority against one authoritative snapshot.
pub fn inspect_token_2022_metadata_authority_postcondition(
account: &kb_lib::MdPubkey,
expected_authority: std::option::Option<&kb_lib::MdPubkey>,
snapshot: &crate::Token2022StatefulSnapshotBundle,
) -> crate::Token2022ExecutionPostcondition {
if snapshot.account_key != account.0 {
return crate::Token2022ExecutionPostcondition {
role: "metadata".to_string(),
account: account.clone(),
status: crate::Token2022ExecutionPostconditionStatus::Contradicted,
diagnostic: "Token-2022 metadata snapshot belongs to a different account".to_string(),
};
}
let output = snapshot.outputs.iter().find(|output| {
return output.family == kb_lib::MdMaterializedEventFamily::Metadata
&& output.payload_json.get("projectionKind").and_then(serde_json::Value::as_str)
== std::option::Option::Some("token_metadata");
});
let observed = output.and_then(|value| {
return value.payload_json.get("valueFields").and_then(|fields| {
return fields.get("updateAuthority");
});
});
let confirmed = match (expected_authority, observed) {
(std::option::Option::Some(expected), std::option::Option::Some(value)) => {
value.as_str() == std::option::Option::Some(expected.0.as_str())
},
(std::option::Option::None, std::option::Option::Some(value)) => value.is_null(),
_ => false,
};
return crate::Token2022ExecutionPostcondition {
role: "metadata".to_string(),
account: account.clone(),
status: if confirmed {
crate::Token2022ExecutionPostconditionStatus::Confirmed
} else {
crate::Token2022ExecutionPostconditionStatus::Contradicted
},
diagnostic: if confirmed {
"authoritative Token-2022 metadata snapshot matches the expected update authority"
.to_string()
} else {
"authoritative Token-2022 metadata snapshot contradicts or omits the expected update authority"
.to_string()
},
};
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
fn simulation(data: &[u8]) -> kb_lib::ExApiExecutionSimulationResult {
return kb_lib::ExApiExecutionSimulationResult {
simulated: true,
success: true,
cluster: kb_lib::ExApiExecutionCluster::Devnet,
blockhash_kind: kb_lib::ExApiExecutionBlockhashKind::Latest,
blockhash_age_slots: std::option::Option::Some(0),
replacement_blockhash: std::option::Option::None,
replacement_last_valid_block_height: std::option::Option::None,
nonce_account: std::option::Option::None,
nonce_authority: std::option::Option::None,
units_consumed: std::option::Option::Some(1),
estimated_fee_lamports: std::option::Option::Some(5_000),
logs: std::vec::Vec::new(),
return_data: std::option::Option::Some(serde_json::json!({
"programId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"data": [base64::engine::general_purpose::STANDARD.encode(data), "base64"]
})),
error: std::option::Option::None,
};
}
fn metadata_bytes(authority: std::option::Option<[u8; 32]>) -> std::vec::Vec<u8> {
let mut value = std::vec::Vec::new();
value.extend_from_slice(authority.unwrap_or([0_u8; 32]).as_slice());
value.extend_from_slice([7_u8; 32].as_slice());
for field in ["Token", "TKN", "https://example.invalid/token.json"] {
value.extend_from_slice((field.len() as u32).to_le_bytes().as_slice());
value.extend_from_slice(field.as_bytes());
}
value.extend_from_slice(0_u32.to_le_bytes().as_slice());
return value;
}
#[test]
fn complete_emit_decodes_exact_metadata_and_ranged_emit_keeps_only_bytes() {
let complete = crate::inspect_token_2022_metadata_emit_simulation(
&simulation(metadata_bytes(std::option::Option::Some([9_u8; 32])).as_slice()),
std::option::Option::None,
std::option::Option::None,
)
.unwrap_or_else(|error| panic!("complete Emit evidence failed: {error}"));
assert_eq!(
complete
.decoded_metadata
.as_ref()
.and_then(|value| return value.get("name"))
.and_then(serde_json::Value::as_str),
std::option::Option::Some("Token")
);
let ranged = crate::inspect_token_2022_metadata_emit_simulation(
&simulation(&[1_u8, 2_u8, 3_u8]),
std::option::Option::Some(0),
std::option::Option::Some(3),
)
.unwrap_or_else(|error| panic!("ranged Emit evidence failed: {error}"));
assert!(ranged.decoded_metadata.is_none());
assert_eq!(ranged.data, vec![1_u8, 2_u8, 3_u8]);
}
#[test]
fn emit_range_and_provider_contract_fail_closed() {
assert!(
crate::validate_token_2022_metadata_emit_range(
std::option::Option::Some(2),
std::option::Option::Some(1),
)
.is_err()
);
assert!(
crate::validate_token_2022_metadata_emit_range(
std::option::Option::Some(0),
std::option::Option::Some(1_025),
)
.is_err()
);
assert!(
crate::validate_token_2022_metadata_emit_range(
std::option::Option::Some(1),
std::option::Option::None,
)
.is_err()
);
let mut invalid = simulation(&[1_u8]);
invalid.return_data = std::option::Option::Some(serde_json::json!({
"programId": kb_program_ids::SYSTEM_PROGRAM_ID,
"data": ["AQ==", "base64"]
}));
assert!(
crate::inspect_token_2022_metadata_emit_simulation(
&invalid,
std::option::Option::Some(0),
std::option::Option::Some(1)
)
.is_err()
);
}
#[test]
fn authority_postcondition_accepts_exact_value_and_null() {
let account = kb_lib::MdPubkey(bs58::encode([3_u8; 32]).into_string());
let authority = kb_lib::MdPubkey(bs58::encode([4_u8; 32]).into_string());
let mut snapshot = crate::Token2022StatefulSnapshotBundle {
account_key: account.0.clone(),
slot: 9,
state_kind: "mint".to_string(),
extension_names: vec!["token_metadata".to_string()],
outputs: vec![kb_lib::MtApiMaterializedOutput {
output_key: "metadata".to_string(),
family: kb_lib::MdMaterializedEventFamily::Metadata,
payload_json: serde_json::json!({
"projectionKind": "token_metadata",
"valueFields": {"updateAuthority": authority.0}
}),
}],
};
let confirmed = crate::inspect_token_2022_metadata_authority_postcondition(
&account,
std::option::Option::Some(&authority),
&snapshot,
);
assert_eq!(confirmed.status, crate::Token2022ExecutionPostconditionStatus::Confirmed);
snapshot.outputs[0].payload_json["valueFields"]["updateAuthority"] =
serde_json::Value::Null;
let cleared = crate::inspect_token_2022_metadata_authority_postcondition(
&account,
std::option::Option::None,
&snapshot,
);
assert_eq!(cleared.status, crate::Token2022ExecutionPostconditionStatus::Confirmed);
snapshot.account_key = bs58::encode([8_u8; 32]).into_string();
let wrong_account = crate::inspect_token_2022_metadata_authority_postcondition(
&account,
std::option::Option::None,
&snapshot,
);
assert_eq!(
wrong_account.status,
crate::Token2022ExecutionPostconditionStatus::Contradicted
);
}
}