v0.1.0-pre.011

This commit is contained in:
2026-07-24 14:23:58 +02:00
parent 62bc0ffb44
commit 42e8a203ec
460 changed files with 12005 additions and 7020 deletions

View File

@@ -3,9 +3,9 @@
//! Exact classic SPL Token dispatch for the common decode pipeline.
const TOKEN_SURFACES: &[crate::DecoderSurface] = &[crate::DecoderSurface {
const TOKEN_SURFACES: &[crate::DcApiDecoderSurface] = &[crate::DcApiDecoderSurface {
program_id: kb_program_ids::SPL_TOKEN_PROGRAM_ID,
surface_code: crate::SPL_TOKEN_SURFACE_CODE,
surface_code: crate::DC_SPL_TOKEN_SURFACE_CODE,
priority: 100,
}];
@@ -13,9 +13,9 @@ const PROGRAM_IDS: &[&str] = &[kb_program_ids::SPL_TOKEN_PROGRAM_ID];
/// Exact decoder for the classic SPL Token program.
#[derive(Clone, Debug, Default)]
pub struct SplTokenDecoder;
pub struct DcSplTokenDecoder;
impl crate::ProtocolDecoder for crate::SplTokenDecoder {
impl crate::DcApiProtocolDecoder for crate::DcSplTokenDecoder {
fn decoder_name(&self) -> &'static str {
return "kb_decoder_spl_token";
}
@@ -30,45 +30,45 @@ impl crate::ProtocolDecoder for crate::SplTokenDecoder {
fn supports_observation(
&self,
observation: &crate::ProgramObservation,
) -> crate::DecoderSupport {
return if crate::ProtocolDecoder::handles_program_id(self, &observation.program_id) {
crate::DecoderSupport::Yes
observation: &crate::MdProgramObservation,
) -> crate::DcApiDecoderSupport {
return if crate::DcApiProtocolDecoder::handles_program_id(self, &observation.program_id) {
crate::DcApiDecoderSupport::Yes
} else {
crate::DecoderSupport::No
crate::DcApiDecoderSupport::No
};
}
fn decode_observation(
&self,
_observation: &crate::ProgramObservation,
) -> kb_core::Result<std::vec::Vec<crate::DecodedProtocolEvent>> {
_observation: &crate::MdProgramObservation,
) -> kb_core::Result<std::vec::Vec<crate::MdDecodedProtocolEvent>> {
return std::result::Result::Ok(std::vec::Vec::new());
}
}
impl crate::InstructionDecoder for crate::SplTokenDecoder {
fn identity(&self) -> crate::DecoderIdentity {
return crate::DecoderIdentity {
impl crate::DcApiInstructionDecoder for crate::DcSplTokenDecoder {
fn identity(&self) -> crate::DcApiDecoderIdentity {
return crate::DcApiDecoderIdentity {
name: "spl_token".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
};
}
fn surfaces(&self) -> &'static [crate::DecoderSurface] {
fn surfaces(&self) -> &'static [crate::DcApiDecoderSurface] {
return TOKEN_SURFACES;
}
fn coverage(&self) -> std::vec::Vec<crate::DecoderCoverageDeclaration> {
return crate::SPL_TOKEN_INSTRUCTION_ENTRIES
fn coverage(&self) -> std::vec::Vec<crate::DcApiDecoderCoverageDeclaration> {
return crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES
.iter()
.map(|(tag, code, historical)| {
return crate::DecoderCoverageDeclaration {
return crate::DcApiDecoderCoverageDeclaration {
program_id: kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string(),
surface_code: std::option::Option::Some(
crate::SPL_TOKEN_SURFACE_CODE.to_string(),
crate::DC_SPL_TOKEN_SURFACE_CODE.to_string(),
),
entry_kind: crate::DecoderCoverageEntryKind::Instruction,
entry_kind: crate::DcApiDecoderCoverageEntryKind::Instruction,
entry_code: (*code).to_string(),
discriminator_hex: std::option::Option::Some(format!("{tag:02x}")),
historical: *historical,
@@ -77,32 +77,39 @@ impl crate::InstructionDecoder for crate::SplTokenDecoder {
.collect();
}
fn recognize(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderRecognition {
fn recognize(
&self,
input: &crate::MdCoreInstructionReplayInput,
) -> crate::DcApiDecoderRecognition {
if input.program_id != kb_program_ids::SPL_TOKEN_PROGRAM_ID {
return crate::DecoderRecognition::incompatible();
return crate::DcApiDecoderRecognition::incompatible();
}
let tag = crate::spl_token_payload_tag(input);
let entry = tag.and_then(crate::spl_token_entry_for_tag);
return crate::DecoderRecognition::compatible(
let tag = crate::decoder_spl_token_payload_tag(input);
let entry = tag.and_then(crate::decoder_spl_token_entry_for_tag);
return crate::DcApiDecoderRecognition::compatible(
entry.is_some(),
100,
std::option::Option::Some(crate::SPL_TOKEN_SURFACE_CODE.to_string()),
std::option::Option::Some(crate::DC_SPL_TOKEN_SURFACE_CODE.to_string()),
entry.map(|(_, code, _)| return code.to_string()),
tag.map(|value| return format!("{value:02x}")),
);
}
fn decode(&self, input: &crate::CoreInstructionReplayInput) -> crate::DecoderExecutionResult {
fn decode(
&self,
input: &crate::MdCoreInstructionReplayInput,
) -> crate::DcApiDecoderExecutionResult {
if input.program_id != kb_program_ids::SPL_TOKEN_PROGRAM_ID {
return crate::DecoderExecutionResult::unsupported(std::option::Option::None);
return crate::DcApiDecoderExecutionResult::unsupported(std::option::Option::None);
}
let result = crate::spl_token_decode(input);
let result = crate::decoder_spl_token_decode(input);
if matches!(
result.status,
crate::DecoderOutcomeStatus::Failed | crate::DecoderOutcomeStatus::Unsupported
crate::DcApiDecoderOutcomeStatus::Failed
| crate::DcApiDecoderOutcomeStatus::Unsupported
) {
tracing::error!(
target: crate::SPL_TOKEN_TRACING_TARGET,
target: crate::DC_SPL_TOKEN_TRACING_TARGET,
action = "decode_failure",
signature = %input.signature,
slot = input.slot,
@@ -118,7 +125,7 @@ impl crate::InstructionDecoder for crate::SplTokenDecoder {
);
}
tracing::debug!(
target: crate::SPL_TOKEN_TRACING_TARGET,
target: crate::DC_SPL_TOKEN_TRACING_TARGET,
action = "decode",
signature = %input.signature,
instruction_path = %input.instruction_path,
@@ -142,8 +149,8 @@ mod tests {
keys: serde_json::Value,
failed: bool,
path: &str,
) -> crate::CoreInstructionReplayInput {
let result = crate::CoreInstructionReplayInput::new(
) -> crate::MdCoreInstructionReplayInput {
let result = crate::MdCoreInstructionReplayInput::new(
format!("signature:{path}"),
"signature",
42,
@@ -219,21 +226,21 @@ mod tests {
#[test]
fn exact_support_program_id_and_interface_match() {
assert_eq!(spl_token_interface::ID.to_string(), kb_program_ids::SPL_TOKEN_PROGRAM_ID);
let decoder = crate::SplTokenDecoder;
assert_eq!(crate::InstructionDecoder::surfaces(&decoder).len(), 1);
let observation = crate::ProgramObservation {
signature: crate::Signature("signature".to_string()),
slot: crate::Slot(1),
instruction_path: crate::InstructionPath("0".to_string()),
program_id: crate::ProgramId(kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string()),
let decoder = crate::DcSplTokenDecoder;
assert_eq!(crate::DcApiInstructionDecoder::surfaces(&decoder).len(), 1);
let observation = crate::MdProgramObservation {
signature: crate::MdSignature("signature".to_string()),
slot: crate::MdSlot(1),
instruction_path: crate::MdInstructionPath("0".to_string()),
program_id: crate::MdProgramId(kb_program_ids::SPL_TOKEN_PROGRAM_ID.to_string()),
discriminator_8: std::option::Option::None,
data_len: 1,
accounts_len: 0,
failed: false,
};
assert_eq!(
crate::ProtocolDecoder::supports_observation(&decoder, &observation),
crate::DecoderSupport::Yes
crate::DcApiProtocolDecoder::supports_observation(&decoder, &observation),
crate::DcApiDecoderSupport::Yes
);
}
@@ -257,12 +264,12 @@ mod tests {
);
})
.collect::<std::vec::Vec<_>>();
let compiled_entries = crate::SPL_TOKEN_INSTRUCTION_ENTRIES
let compiled_entries = crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES
.iter()
.map(|(tag, code, _)| return (*tag, *code))
.collect::<std::vec::Vec<_>>();
assert_eq!(matrix_entries, compiled_entries);
assert_eq!(crate::InstructionDecoder::coverage(&crate::SplTokenDecoder).len(), 28);
assert_eq!(crate::DcApiInstructionDecoder::coverage(&crate::DcSplTokenDecoder).len(), 28);
}
#[test]
@@ -324,7 +331,7 @@ mod tests {
#[test]
fn every_published_tag_decodes_and_matches_official_unpack() {
for (tag, code, _) in crate::SPL_TOKEN_INSTRUCTION_ENTRIES {
for (tag, code, _) in crate::DC_SPL_TOKEN_INSTRUCTION_ENTRIES {
let wire = minimal_wire(*tag);
let official = spl_token_interface::instruction::TokenInstruction::unpack(&wire);
assert!(official.is_ok(), "official unpack rejected tag {tag}");
@@ -336,8 +343,8 @@ mod tests {
false,
"0",
);
let result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Decoded);
let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert_eq!(result.recognized_entry_code.as_deref(), std::option::Option::Some(*code));
}
}
@@ -364,8 +371,8 @@ mod tests {
true,
"2/1",
);
let result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Decoded);
let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert!(!result.observations[0].observation_committed);
assert_eq!(
result.observations[0].payload_json["parameters"]["amountRaw"],
@@ -374,7 +381,7 @@ mod tests {
assert_eq!(result.observations[0].payload_json["inference"]["mintInvented"], false);
assert_eq!(
result.observations[0].event.source_kind,
crate::EventSourceKind::InnerInstruction
crate::MdEventSourceKind::InnerInstruction
);
}
@@ -390,8 +397,9 @@ mod tests {
false,
"0",
);
let suffix_result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &suffix);
assert_eq!(suffix_result.status, crate::DecoderOutcomeStatus::Decoded);
let suffix_result =
crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &suffix);
assert_eq!(suffix_result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert_eq!(suffix_result.observations[0].payload_json["wire"]["suffixLengthBytes"], 2);
for wire in [std::vec::Vec::new(), std::vec![3, 1], std::vec![24, 0xff], std::vec![255]] {
let input = input(
@@ -402,8 +410,8 @@ mod tests {
false,
"0",
);
let result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &input);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Failed);
let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &input);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Failed);
assert!(result.observations.is_empty());
}
let unknown = input(
@@ -414,8 +422,8 @@ mod tests {
false,
"0",
);
let result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &unknown);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Unsupported);
let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &unknown);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Unsupported);
assert!(!result.diagnostics.is_empty());
}
@@ -432,8 +440,8 @@ mod tests {
false,
"4/2",
);
let result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &cinput);
assert_eq!(result.status, crate::DecoderOutcomeStatus::Decoded);
let result = crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &cinput);
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded);
assert_eq!(result.observations.len(), 3);
assert_eq!(result.observations[1].event.instruction_path.0, "4/2/batch/0");
assert_eq!(result.observations[2].event.instruction_path.0, "4/2/batch/1");
@@ -446,8 +454,9 @@ mod tests {
false,
"0",
);
let nested_result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &nested);
assert_eq!(nested_result.status, crate::DecoderOutcomeStatus::Failed);
let nested_result =
crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &nested);
assert_eq!(nested_result.status, crate::DcApiDecoderOutcomeStatus::Failed);
}
#[test]
@@ -471,7 +480,8 @@ mod tests {
false,
"0",
);
let simple_result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &simple);
let simple_result =
crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &simple);
assert_eq!(simple_result.observations[0].payload_json["authority"]["form"], "single");
let mut multisig_accounts = simple_accounts.as_array().cloned().unwrap_or_default();
multisig_accounts
@@ -490,7 +500,8 @@ mod tests {
false,
"0",
);
let multisig_result = crate::InstructionDecoder::decode(&crate::SplTokenDecoder, &multisig);
let multisig_result =
crate::DcApiInstructionDecoder::decode(&crate::DcSplTokenDecoder, &multisig);
assert_eq!(multisig_result.observations[0].payload_json["authority"]["form"], "multisig");
assert_eq!(
multisig_result.observations[0].payload_json["authority"]["statefulMultisigValidation"],