v0.1.0-pre.008

This commit is contained in:
2026-07-23 20:40:38 +02:00
parent f5bd8fab7f
commit 12b42a31b8
26 changed files with 6686 additions and 280 deletions

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/decoder/spl.rs
// version: 4
// version: 5
//! `spl` decoder family.
@@ -37,6 +37,22 @@ pub(crate) use self::associated_token_account::spl_associated_token_account_deco
pub(crate) use self::associated_token_account::spl_associated_token_account_entry;
/// Reads one bounded Associated Token Account payload.
pub(crate) use self::associated_token_account::spl_associated_token_account_payload;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::ParsedRegistryInstruction;
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use self::elgamal_registry::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use self::elgamal_registry::spl_elgamal_registry_parse;
/// Maximum payload prefix retained for bounded diagnostics.
pub(crate) use self::memo::SPL_MEMO_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Memo decoded event contract version.
@@ -77,10 +93,52 @@ pub(crate) use self::token::spl_token_decode;
pub(crate) use self::token::spl_token_entry_for_tag;
/// Returns the first byte of one retained classic SPL Token payload.
pub(crate) use self::token::spl_token_payload_tag;
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use self::token_2022::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use self::token_2022::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use self::token_2022::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use self::token_2022::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use self::token_2022::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use self::token_2022::SPL_TOKEN_2022_TRACING_TARGET;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use self::token_2022::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use self::token_2022::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use self::token_2022::spl_token_2022_payload_tag;
/// Exact decoder for the SPL Associated Token Account program.
pub use self::associated_token_account::SplAssociatedTokenAccountDecoder;
/// Exact byte length of one SPL ElGamal registry account.
pub use self::elgamal_registry::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use self::elgamal_registry::ElGamalRegistryState;
/// Exact decoder for the SPL ElGamal registry program.
pub use self::elgamal_registry::SplElgamalRegistryDecoder;
/// Parses one exact SPL ElGamal registry account.
pub use self::elgamal_registry::parse_elgamal_registry_state;
/// Exact decoder for the three registered SPL Memo generations.
pub use self::memo::SplMemoDecoder;
/// Exact decoder for the classic SPL Token program.
pub use self::token::SplTokenDecoder;
/// Exact decoder for the Token-2022 program.
pub use self::token_2022::SplToken2022Decoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use self::token_2022::Token2022State;
/// Exact Token-2022 base account state kind.
pub use self::token_2022::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use self::token_2022::Token2022TlvEntry;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::token_2022::parse_token_2022_state;

View File

@@ -1,10 +1,35 @@
// file: kb-lib/src/decoder/spl/elgamal_registry.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_decoder_spl_elgamal_registry`.
//! Exact SPL Token-2022 ElGamal public-key registry decoder component.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_decoder_spl_elgamal_registry";
mod constants;
mod decoder;
mod state;
mod wire;
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
/// Current stable SPL ElGamal registry event contract version.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_EVENT_VERSION;
/// Maximum retained SPL ElGamal registry instruction payload size.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES;
/// Stable SPL ElGamal registry surface code.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_SURFACE_CODE;
/// Canonical tracing target for the SPL ElGamal registry decoder.
pub(crate) use self::constants::SPL_ELGAMAL_REGISTRY_TRACING_TARGET;
/// One parsed SPL ElGamal registry instruction.
pub(crate) use self::wire::ParsedRegistryInstruction;
/// Decodes one bounded SPL ElGamal registry instruction.
pub(crate) use self::wire::spl_elgamal_registry_decode;
/// Decodes one bounded SPL ElGamal registry instruction payload.
pub(crate) use self::wire::spl_elgamal_registry_decode_payload;
/// Parses one exact SPL ElGamal registry instruction.
pub(crate) use self::wire::spl_elgamal_registry_parse;
/// Exact decoder for the SPL ElGamal registry program.
pub use self::decoder::SplElgamalRegistryDecoder;
/// Exact byte length of one SPL ElGamal registry account.
pub use self::state::ELGAMAL_REGISTRY_ACCOUNT_LEN;
/// Parsed SPL ElGamal public-key registry account.
pub use self::state::ElGamalRegistryState;
/// Parses one exact SPL ElGamal registry account.
pub use self::state::parse_elgamal_registry_state;

View File

@@ -0,0 +1,11 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/constants.rs
// version: 1
//! Constants for the SPL ElGamal registry decoder.
pub(crate) const SPL_ELGAMAL_REGISTRY_SURFACE_CODE: &str = "spl_elgamal_registry";
pub(crate) const SPL_ELGAMAL_REGISTRY_EVENT_VERSION: u32 = 1;
pub(crate) const SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES: usize = 16;
/// Canonical tracing target for this crate.
pub(crate) const SPL_ELGAMAL_REGISTRY_TRACING_TARGET: &str = "kb-lib.decoder.spl.elgamal_registry";

View File

@@ -0,0 +1,246 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/decoder.rs
// version: 1
//! Exact dispatch for the SPL ElGamal registry program.
const SURFACES: &[crate::DecoderSurface] = &[crate::DecoderSurface {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
surface_code: crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE,
priority: 100,
}];
const PROGRAM_IDS: &[&str] = &[kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID];
/// Decoder for the dedicated Token-2022 ElGamal public-key registry program.
#[derive(Clone, Debug, Default)]
pub struct SplElgamalRegistryDecoder;
impl crate::ProtocolDecoder for crate::SplElgamalRegistryDecoder {
fn decoder_name(&self) -> &'static str {
return "kb_decoder_spl_elgamal_registry";
}
fn decoder_version(&self) -> &'static str {
return env!("CARGO_PKG_VERSION");
}
fn program_ids(&self) -> &'static [&'static str] {
return PROGRAM_IDS;
}
fn supports_observation(
&self,
observation: &crate::ProgramObservation,
) -> crate::DecoderSupport {
return if crate::ProtocolDecoder::handles_program_id(self, &observation.program_id) {
crate::DecoderSupport::Yes
} else {
crate::DecoderSupport::No
};
}
fn decode_observation(
&self,
_observation: &crate::ProgramObservation,
) -> kb_core::Result<std::vec::Vec<crate::DecodedProtocolEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl crate::InstructionDecoder for crate::SplElgamalRegistryDecoder {
fn identity(&self) -> crate::DecoderIdentity {
return crate::DecoderIdentity {
name: "spl_elgamal_registry".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn surfaces(&self) -> &'static [crate::DecoderSurface] {
return SURFACES;
}
fn coverage(&self) -> std::vec::Vec<crate::DecoderCoverageDeclaration> {
return [(0_u8, "create_registry"), (1_u8, "update_registry")]
.into_iter()
.map(|(tag, code)| {
return crate::DecoderCoverageDeclaration {
program_id: kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
.to_string(),
surface_code: std::option::Option::Some(
crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string(),
),
entry_kind: crate::DecoderCoverageEntryKind::Instruction,
entry_code: code.to_string(),
discriminator_hex: std::option::Option::Some(format!("{tag:02x}")),
historical: false,
};
})
.collect();
}
fn recognize(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderRecognition {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return crate::DecoderRecognition::incompatible();
}
let entry = input
.instruction_payload_json
.as_ref()
.and_then(|payload| return payload.get("dataBase64"))
.and_then(serde_json::Value::as_str)
.and_then(|encoded| {
use base64::Engine; // rust-rules: trait-import
return base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()).ok();
})
.and_then(|bytes| return bytes.first().copied())
.and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
});
return crate::DecoderRecognition::compatible(
entry.is_some(),
100,
std::option::Option::Some(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
entry,
std::option::Option::None,
);
}
fn decode(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderExecutionResult {
if input.program_id != kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID {
return crate::DecoderExecutionResult::unsupported(std::option::Option::None);
}
let result = crate::spl_elgamal_registry_decode(input);
if matches!(
result.status,
crate::DecoderOutcomeStatus::Failed | crate::DecoderOutcomeStatus::Unsupported
) {
tracing::error!(
target: crate::SPL_ELGAMAL_REGISTRY_TRACING_TARGET,
action = "decode_failure",
signature = %input.signature,
slot = input.slot,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
processor_name = "spl_elgamal_registry",
processor_version = env!("CARGO_PKG_VERSION"),
input_key = %input.replay_input_key,
payload_hash = ?input.instruction_payload_hash,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
diagnostics = ?result.diagnostics,
"SPL ElGamal registry instruction was not decoded successfully"
);
}
tracing::debug!(
target: crate::SPL_ELGAMAL_REGISTRY_TRACING_TARGET,
action = "decode",
signature = %input.signature,
instruction_path = %input.instruction_path,
program_id = %input.program_id,
transaction_failed = input.transaction_failed,
result_status = ?result.status,
observation_count = result.observations.len(),
"SPL ElGamal registry instruction decode completed"
);
return result;
}
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
fn input(
program_id: &str,
payload: &[u8],
failed: bool,
path: &str,
) -> crate::CoreInstructionReplayInput {
let result = crate::CoreInstructionReplayInput::new(
format!("signature:{path}"),
"signature",
42,
path,
program_id,
failed,
if failed {
std::option::Option::Some(serde_json::json!({"InstructionError":[0,"Custom"]}))
} else {
std::option::Option::None
},
serde_json::json!([]),
serde_json::json!([]),
std::option::Option::Some(serde_json::json!({
"dataBase64": base64::engine::general_purpose::STANDARD.encode(payload)
})),
std::option::Option::None,
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
serde_json::json!([]),
);
return match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("registry replay input failed: {error}"),
};
}
#[test]
fn exact_program_boundary_and_interface_id_are_preserved() {
assert_eq!(
spl_elgamal_registry_interface::id().to_string(),
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID
);
let decoder = crate::SplElgamalRegistryDecoder;
assert_eq!(crate::InstructionDecoder::coverage(&decoder).len(), 2);
let foreign = input(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID, &[0, 1], false, "0");
assert_eq!(
crate::InstructionDecoder::decode(&decoder, &foreign).status,
crate::DecoderOutcomeStatus::Unsupported
);
}
#[test]
fn create_and_update_decode_exact_offsets_and_commit_state() {
for (tag, code, offset, failed, path) in [
(0_u8, "create_registry", 1_i8, false, "0"),
(1_u8, "update_registry", -1_i8, true, "1/0"),
(1_u8, "update_registry", 0_i8, false, "2"),
] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
&[tag, offset as u8],
failed,
path,
);
let result =
crate::InstructionDecoder::decode(&crate::SplElgamalRegistryDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some(code));
assert_eq!(
result.observations[0].payload_json["proofInstructionOffset"],
serde_json::json!(offset)
);
assert_eq!(result.observations[0].observation_committed, !failed);
}
}
#[test]
fn malformed_unknown_and_suffixed_wire_fail_closed() {
for payload in [std::vec::Vec::new(), vec![0], vec![2, 0], vec![0, 1, 2]] {
let input = input(
kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
payload.as_slice(),
false,
"0",
);
let result =
crate::InstructionDecoder::decode(&crate::SplElgamalRegistryDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Failed);
assert!(result.observations.is_empty());
}
}
}

View File

@@ -0,0 +1,76 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/state.rs
// version: 1
//! Strict SPL ElGamal registry account-state parsing.
use base64::Engine; // rust-rules: trait-import
/// Exact byte length of one SPL ElGamal registry account.
pub const ELGAMAL_REGISTRY_ACCOUNT_LEN: usize = 64;
/// Public state retained by one SPL ElGamal registry account.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ElGamalRegistryState {
/// Wallet address associated with this registry.
pub owner: String,
/// Exact 32-byte ElGamal public key encoded as standard base64.
pub elgamal_pubkey_base64: String,
/// Exact account bytes encoded as lowercase hexadecimal.
pub wire_hex: String,
}
/// Parse one exact SPL ElGamal registry account.
pub fn parse_elgamal_registry_state(
data: &[u8],
) -> std::result::Result<ElGamalRegistryState, std::string::String> {
if data.len() != ELGAMAL_REGISTRY_ACCOUNT_LEN {
return std::result::Result::Err(format!(
"SPL ElGamal registry account requires exactly {ELGAMAL_REGISTRY_ACCOUNT_LEN} bytes; received {}",
data.len()
));
}
return std::result::Result::Ok(ElGamalRegistryState {
owner: bs58::encode(&data[..32]).into_string(),
elgamal_pubkey_base64: base64::engine::general_purpose::STANDARD.encode(&data[32..64]),
wire_hex: lower_hex(data),
});
}
fn lower_hex(bytes: &[u8]) -> String {
let mut output = String::with_capacity(bytes.len() * 2);
for byte in bytes {
output.push_str(&format!("{byte:02x}"));
}
return output;
}
#[cfg(test)]
mod tests {
use base64::Engine; // rust-rules: trait-import
#[test]
fn exact_registry_state_preserves_owner_key_and_wire() {
let mut data = [0u8; crate::ELGAMAL_REGISTRY_ACCOUNT_LEN];
data[..32].fill(7);
data[32..].fill(9);
let parsed = crate::parse_elgamal_registry_state(&data);
assert_eq!(
parsed.as_ref().map(|state| return state.owner.clone()),
std::result::Result::Ok(bs58::encode([7u8; 32]).into_string())
);
assert_eq!(
parsed.as_ref().map(|state| return state.elgamal_pubkey_base64.clone()),
std::result::Result::Ok(base64::engine::general_purpose::STANDARD.encode([9u8; 32]))
);
assert_eq!(
parsed.as_ref().map(|state| return state.wire_hex.len()),
std::result::Result::Ok(128)
);
}
#[test]
fn registry_state_rejects_every_non_exact_length() {
assert!(crate::parse_elgamal_registry_state(&[0; 63]).is_err());
assert!(crate::parse_elgamal_registry_state(&[0; 65]).is_err());
}
}

View File

@@ -0,0 +1,195 @@
// file: kb-lib/src/decoder/spl/elgamal_registry/wire.rs
// version: 1
//! Exact two-byte SPL ElGamal registry instruction decoding.
use base64::Engine; // rust-rules: trait-import
use sha2::Digest; // rust-rules: trait-import
#[derive(Clone, Debug)]
pub(crate) struct ParsedRegistryInstruction {
pub(crate) code: &'static str,
pub(crate) tag: u8,
pub(crate) proof_instruction_offset: i8,
}
pub(crate) fn spl_elgamal_registry_decode_payload(
input: &crate::CoreInstructionReplayInput,
) -> std::result::Result<std::vec::Vec<u8>, std::string::String> {
let payload = match input.instruction_payload_json.as_ref() {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry instruction payload is not retained".to_string(),
);
},
};
let encoded = match payload.get("dataBase64").and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
"ElGamal registry payload does not contain dataBase64".to_string(),
);
},
};
if encoded.len() > 32 {
return std::result::Result::Err(
"ElGamal registry base64 payload is too large".to_string(),
);
}
let bytes = match base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(format!(
"ElGamal registry payload is not valid base64: {error}"
));
},
};
if bytes.len() > crate::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES {
return std::result::Result::Err(format!(
"ElGamal registry payload exceeds {} bytes",
crate::SPL_ELGAMAL_REGISTRY_MAX_INSTRUCTION_BYTES
));
}
return std::result::Result::Ok(bytes);
}
pub(crate) fn spl_elgamal_registry_parse(
bytes: &[u8],
) -> std::result::Result<crate::ParsedRegistryInstruction, std::string::String> {
if bytes.len() != 2 {
return std::result::Result::Err(format!(
"ElGamal registry instruction requires exactly 2 bytes; received {}",
bytes.len()
));
}
let code = match bytes[0] {
0 => "create_registry",
1 => "update_registry",
tag => return std::result::Result::Err(format!("unknown ElGamal registry tag {tag}")),
};
return std::result::Result::Ok(crate::ParsedRegistryInstruction {
code,
tag: bytes[0],
proof_instruction_offset: bytes[1] as i8,
});
}
pub(crate) fn spl_elgamal_registry_decode(
input: &crate::CoreInstructionReplayInput,
) -> crate::DecoderExecutionResult {
let bytes = match crate::spl_elgamal_registry_decode_payload(input) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Failed,
recognized_entry_code: std::option::Option::None,
observations: std::vec::Vec::new(),
diagnostics: std::vec![crate::DecoderDiagnostic {
code: "elgamal_registry_payload_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let parsed = match crate::spl_elgamal_registry_parse(bytes.as_slice()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(message) => {
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Failed,
recognized_entry_code: bytes.first().and_then(|tag| {
return match tag {
0 => std::option::Option::Some("create_registry".to_string()),
1 => std::option::Option::Some("update_registry".to_string()),
_ => std::option::Option::None,
};
}),
observations: std::vec::Vec::new(),
diagnostics: std::vec![crate::DecoderDiagnostic {
code: "elgamal_registry_wire_invalid".to_string(),
message,
retriable: false,
}],
};
},
};
let committed = !input.transaction_failed;
let wire_hash = hash(bytes.as_slice());
let event = crate::DecodedProtocolEvent {
signature: crate::Signature(input.signature.clone()),
slot: crate::Slot(input.slot),
instruction_path: crate::InstructionPath(input.instruction_path.clone()),
program_id: crate::ProgramId(input.program_id.clone()),
protocol_code: crate::ProtocolCode(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
surface_code: crate::SurfaceCode(crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE.to_string()),
event_code: crate::EventCode(format!(
"{}.{}",
crate::SPL_ELGAMAL_REGISTRY_SURFACE_CODE,
parsed.code
)),
event_name: crate::EventName(parsed.code.to_string()),
event_family: crate::EventFamily::Admin,
source_kind: if input.instruction_path.contains('/') {
crate::EventSourceKind::InnerInstruction
} else {
crate::EventSourceKind::Instruction
},
confidence: crate::DecoderConfidence::ManualExact,
};
let observation = crate::DecodedObservation {
event_key: format!("elgamal_registry:{}:0", parsed.code),
event,
payload_json: serde_json::json!({
"eventVersion": crate::SPL_ELGAMAL_REGISTRY_EVENT_VERSION,
"instruction": parsed.code,
"wireTag": parsed.tag,
"proofInstructionOffset": parsed.proof_instruction_offset,
"proofLocationKind": if parsed.proof_instruction_offset == 0 { "context_state_account" } else { "relative_instruction_offset" },
"instructionPath": input.instruction_path,
"instructionLocation": if input.instruction_path.contains('/') { "inner" } else { "outer" },
"transactionSucceeded": !input.transaction_failed,
"committed": committed,
"accounts": input.instruction_accounts_json,
"wire": {
"lengthBytes": bytes.len(),
"sha256": wire_hash,
"prefixHex": hex(bytes.as_slice()),
"complete": true,
},
"programBoundary": {
"registryProgramId": kb_program_ids::SPL_TOKEN_2022_ELGAMAL_REGISTRY_PROGRAM_ID,
"token2022ProgramId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
"zkProofProgramId": kb_program_ids::ZK_ELGAMAL_PROOF_PROGRAM_ID,
"proofDecodedHere": false,
}
}),
transaction_failed: input.transaction_failed,
transaction_error: input.transaction_err_json.clone(),
observation_committed: committed,
proof: crate::DecoderProof {
kind: crate::DecoderProofKind::Manual,
confidence: crate::DecoderConfidence::ManualExact,
evidence: std::vec![
"spl_elgamal_registry_interface_0_2_1_registry_instruction_unpack".to_string(),
format!("wire_tag:{}", parsed.tag),
format!("wire_sha256:{wire_hash}"),
],
},
};
return crate::DecoderExecutionResult {
status: crate::DecoderOutcomeStatus::Decoded,
recognized_entry_code: std::option::Option::Some(parsed.code.to_string()),
observations: std::vec![observation],
diagnostics: std::vec::Vec::new(),
};
}
fn hash(bytes: &[u8]) -> std::string::String {
let digest = sha2::Sha256::digest(bytes);
return digest.iter().map(|byte| return format!("{byte:02x}")).collect();
}
fn hex(bytes: &[u8]) -> std::string::String {
return bytes.iter().map(|byte| return format!("{byte:02x}")).collect();
}

View File

@@ -1,10 +1,45 @@
// file: kb-lib/src/decoder/spl/token_2022.rs
// version: 1
// version: 2
//! Migration boundary for legacy crate `kb_decoder_spl_token_2022`.
//! Exact Token-2022 instruction and state decoder component.
/// Legacy crate name retained for migration and compatibility tracking.
pub const LEGACY_CRATE: &str = "kb_decoder_spl_token_2022";
mod constants;
mod decoder;
mod state;
mod wire;
/// Current porting status.
pub const MIGRATION_STATUS: &str = "source-preserved-pending-port";
/// Maximum prefix retained in bounded Token-2022 diagnostics.
pub(crate) use self::constants::SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
/// Current stable Token-2022 decoded event contract version.
pub(crate) use self::constants::SPL_TOKEN_2022_EVENT_VERSION;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) use self::constants::SPL_TOKEN_2022_INSTRUCTION_ENTRIES;
/// Maximum total account metas consumed by one Token-2022 batch.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS;
/// Maximum decoded sub-instructions in one Token-2022 batch.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS;
/// Maximum retained Token-2022 instruction payload size.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) use self::constants::SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES;
/// Stable Token-2022 surface code.
pub(crate) use self::constants::SPL_TOKEN_2022_SURFACE_CODE;
/// Canonical tracing target for the Token-2022 decoder.
pub(crate) use self::constants::SPL_TOKEN_2022_TRACING_TARGET;
/// Decodes one bounded Token-2022 instruction.
pub(crate) use self::wire::spl_token_2022_decode;
/// Returns the exact entry matching one Token-2022 tag.
pub(crate) use self::wire::spl_token_2022_entry_for_tag;
/// Returns the first byte of one retained Token-2022 payload.
pub(crate) use self::wire::spl_token_2022_payload_tag;
/// Exact decoder for the Token-2022 program.
pub use self::decoder::SplToken2022Decoder;
/// Parsed Token-2022 Mint, Account, or Multisig state.
pub use self::state::Token2022State;
/// Exact Token-2022 base account state kind.
pub use self::state::Token2022StateKind;
/// One exact Token-2022 TLV entry.
pub use self::state::Token2022TlvEntry;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::state::parse_token_2022_state;

View File

@@ -0,0 +1,72 @@
// file: kb-lib/src/decoder/spl/token_2022/constants.rs
// version: 1
//! Local constants for the exact Token-2022 decoder. Program identifiers live in `kb_program_ids`.
/// Stable Token-2022 surface code.
pub(crate) const SPL_TOKEN_2022_SURFACE_CODE: &str = "spl_token_2022";
/// Current decoded event contract version.
pub(crate) const SPL_TOKEN_2022_EVENT_VERSION: u32 = 1;
/// Maximum retained instruction payload size.
pub(crate) const SPL_TOKEN_2022_MAX_INSTRUCTION_BYTES: usize = 16_384;
/// Maximum retained UTF-8 string size for embedded Token Metadata instructions.
pub(crate) const SPL_TOKEN_2022_MAX_METADATA_STRING_BYTES: usize = 4_096;
/// Maximum prefix retained in diagnostics.
pub(crate) const SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES: usize = 32;
/// Maximum decoded sub-instructions in one batch.
pub(crate) const SPL_TOKEN_2022_MAX_BATCH_INSTRUCTIONS: usize = 64;
/// Maximum total account metas consumed by one batch.
pub(crate) const SPL_TOKEN_2022_MAX_BATCH_ACCOUNTS: usize = 512;
/// Exact top-level instruction inventory published by the resolved Token-2022 interface.
pub(crate) const SPL_TOKEN_2022_INSTRUCTION_ENTRIES: &[(u8, &str, bool)] = &[
(0, "initialize_mint", false),
(1, "initialize_account", false),
(2, "initialize_multisig", false),
(3, "transfer", false),
(4, "approve", false),
(5, "revoke", false),
(6, "set_authority", false),
(7, "mint_to", false),
(8, "burn", false),
(9, "close_account", false),
(10, "freeze_account", false),
(11, "thaw_account", false),
(12, "transfer_checked", false),
(13, "approve_checked", false),
(14, "mint_to_checked", false),
(15, "burn_checked", false),
(16, "initialize_account2", false),
(17, "sync_native", false),
(18, "initialize_account3", false),
(19, "initialize_multisig2", false),
(20, "initialize_mint2", false),
(21, "get_account_data_size", false),
(22, "initialize_immutable_owner", false),
(23, "amount_to_ui_amount", false),
(24, "ui_amount_to_amount", false),
(25, "initialize_mint_close_authority", false),
(26, "transfer_fee_extension", false),
(27, "confidential_transfer_extension", false),
(28, "default_account_state_extension", false),
(29, "reallocate", false),
(30, "memo_transfer_extension", false),
(31, "create_native_mint", false),
(32, "initialize_non_transferable_mint", false),
(33, "interest_bearing_mint_extension", false),
(34, "cpi_guard_extension", false),
(35, "initialize_permanent_delegate", false),
(36, "transfer_hook_extension", false),
(37, "confidential_transfer_fee_extension", false),
(38, "withdraw_excess_lamports", false),
(39, "metadata_pointer_extension", false),
(40, "group_pointer_extension", false),
(41, "group_member_pointer_extension", false),
(42, "confidential_mint_burn_extension", false),
(43, "scaled_ui_amount_extension", false),
(44, "pausable_extension", false),
(45, "unwrap_lamports", false),
(46, "permissioned_burn_extension", false),
(255, "batch", false),
];
/// Canonical tracing target for this crate.
pub(crate) const SPL_TOKEN_2022_TRACING_TARGET: &str = "kb-lib.decoder.spl.token_2022";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff