v0.4.8-pre.008
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder/metadata/solana_program_metadata/instruction.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Exact contextual instruction decoding for Solana Program Metadata.
|
||||
|
||||
@@ -627,9 +627,15 @@ fn validate_accounts(
|
||||
));
|
||||
},
|
||||
};
|
||||
if account.signer != contract.signer || account.writable != contract.writable {
|
||||
if contract.signer && !account.signer {
|
||||
return std::result::Result::Err(format!(
|
||||
"{} account {position} ({}) has invalid signer/writable flags",
|
||||
"{} account {position} ({}) is missing the required signer privilege",
|
||||
parsed.code, contract.role
|
||||
));
|
||||
}
|
||||
if contract.writable && !account.writable {
|
||||
return std::result::Result::Err(format!(
|
||||
"{} account {position} ({}) is missing the required writable privilege",
|
||||
parsed.code, contract.role
|
||||
));
|
||||
}
|
||||
@@ -1160,6 +1166,115 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_wide_privilege_supersets_are_accepted() {
|
||||
let cases = [
|
||||
(
|
||||
vec![0, 4, 0, 0, 0, 1, 2],
|
||||
vec![
|
||||
("buffer", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"write",
|
||||
),
|
||||
(
|
||||
[vec![1], vec![0; 16], vec![1, 0, 1, 0], vec![1]].concat(),
|
||||
vec![
|
||||
("metadata", false, true),
|
||||
("authority", true, true),
|
||||
("program", false, false),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"initialize",
|
||||
),
|
||||
(
|
||||
vec![2, 0],
|
||||
vec![
|
||||
("account", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"set_authority",
|
||||
),
|
||||
(
|
||||
vec![3, 1, 0, 1],
|
||||
vec![
|
||||
("metadata", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"set_data",
|
||||
),
|
||||
(
|
||||
vec![4],
|
||||
vec![
|
||||
("metadata", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"set_immutable",
|
||||
),
|
||||
(
|
||||
vec![5],
|
||||
vec![
|
||||
("account", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
("destination", false, true),
|
||||
("SysvarRent111111111111111111111111111111111", false, false),
|
||||
],
|
||||
"trim",
|
||||
),
|
||||
(
|
||||
vec![6],
|
||||
vec![
|
||||
("account", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
("destination", false, true),
|
||||
],
|
||||
"close",
|
||||
),
|
||||
(
|
||||
[vec![7], vec![8; 16]].concat(),
|
||||
vec![
|
||||
("buffer", false, true),
|
||||
("authority", true, true),
|
||||
("program", false, false),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"allocate",
|
||||
),
|
||||
(
|
||||
vec![8, 32, 0],
|
||||
vec![
|
||||
("account", false, true),
|
||||
("authority", true, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
"extend",
|
||||
),
|
||||
];
|
||||
for (payload, accounts, expected) in cases {
|
||||
let result = decode(payload.as_slice(), accounts.as_slice());
|
||||
assert_eq!(result.status, crate::DcApiDecoderOutcomeStatus::Decoded, "{expected}");
|
||||
assert_eq!(
|
||||
result.recognized_entry_code.as_deref(),
|
||||
std::option::Option::Some(expected)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_selection_and_account_flags_fail_closed() {
|
||||
let invalid_write = decode(
|
||||
@@ -1199,6 +1314,16 @@ mod tests {
|
||||
],
|
||||
);
|
||||
assert_eq!(invalid_flags.status, crate::DcApiDecoderOutcomeStatus::Failed);
|
||||
let missing_signer = decode(
|
||||
&[8, 1, 0],
|
||||
&[
|
||||
("account", false, true),
|
||||
("authority", false, true),
|
||||
(placeholder(), false, false),
|
||||
(placeholder(), false, false),
|
||||
],
|
||||
);
|
||||
assert_eq!(missing_signer.status, crate::DcApiDecoderOutcomeStatus::Failed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder/spl/token_2022/wire.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Bounded Token-2022 wire, account and authority decoding.
|
||||
|
||||
@@ -2532,10 +2532,7 @@ fn event_family(code: &str) -> crate::MdEventFamily {
|
||||
| "initialize_multisig2"
|
||||
| "initialize_permanent_delegate"
|
||||
| "initialize_interest_bearing_mint"
|
||||
| "update_interest_bearing_rate"
|
||||
| "update_token_metadata_authority"
|
||||
| "update_token_group_authority"
|
||||
| "update_token_group_max_size" => crate::MdEventFamily::Admin,
|
||||
| "update_interest_bearing_rate" => crate::MdEventFamily::Admin,
|
||||
"initialize_mint"
|
||||
| "initialize_mint2"
|
||||
| "mint_to"
|
||||
@@ -2564,8 +2561,11 @@ fn event_family(code: &str) -> crate::MdEventFamily {
|
||||
"initialize_token_metadata"
|
||||
| "update_token_metadata_field"
|
||||
| "remove_token_metadata_key"
|
||||
| "update_token_metadata_authority"
|
||||
| "emit_token_metadata"
|
||||
| "initialize_token_group"
|
||||
| "update_token_group_max_size"
|
||||
| "update_token_group_authority"
|
||||
| "initialize_token_group_member" => crate::MdEventFamily::Metadata,
|
||||
"batch" | "get_account_data_size" | "amount_to_ui_amount" | "ui_amount_to_amount" => {
|
||||
crate::MdEventFamily::Audit
|
||||
@@ -2608,3 +2608,23 @@ fn failed(
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod metadata_family_tests {
|
||||
#[test]
|
||||
fn every_embedded_metadata_and_group_instruction_uses_metadata_family() {
|
||||
for operation in [
|
||||
"initialize_token_metadata",
|
||||
"update_token_metadata_field",
|
||||
"remove_token_metadata_key",
|
||||
"update_token_metadata_authority",
|
||||
"emit_token_metadata",
|
||||
"initialize_token_group",
|
||||
"update_token_group_max_size",
|
||||
"update_token_group_authority",
|
||||
"initialize_token_group_member",
|
||||
] {
|
||||
assert_eq!(super::event_family(operation), crate::MdEventFamily::Metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/lib.rs
|
||||
// version: 36
|
||||
// version: 37
|
||||
|
||||
//! Consolidated decoder, executor, materializer and shared model library.
|
||||
#![warn(missing_docs)]
|
||||
@@ -1439,8 +1439,12 @@ pub use self::materializer::MtLifecycleMaterializer;
|
||||
pub use self::materializer::MtLiquidityMaterializer;
|
||||
/// Exposes the legacy common business materializer trait.
|
||||
pub use self::materializer::MtMaterializer;
|
||||
/// Compatibility wrapper for the Solana Program Metadata materializer.
|
||||
pub use self::materializer::MtMetadataMaterializer;
|
||||
/// Metaplex Token Metadata instruction materializer.
|
||||
pub use self::materializer::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
/// Solana Program Metadata instruction materializer.
|
||||
pub use self::materializer::MtMetadataSolanaProgramMaterializer;
|
||||
/// SPL Token-2022 embedded metadata and group instruction materializer.
|
||||
pub use self::materializer::MtMetadataToken2022Materializer;
|
||||
/// Reserved NFT materializer.
|
||||
pub use self::materializer::MtNftMaterializer;
|
||||
/// Reserved oracle materializer.
|
||||
@@ -1457,8 +1461,6 @@ pub use self::materializer::MtRewardsMaterializer;
|
||||
pub use self::materializer::MtRiskMaterializer;
|
||||
/// Reserved routing materializer.
|
||||
pub use self::materializer::MtRoutingMaterializer;
|
||||
/// Stable Solana Program Metadata instruction materializer.
|
||||
pub use self::materializer::MtSolanaProgramMetadataMaterializer;
|
||||
/// Stable native stake and vote materializer.
|
||||
pub use self::materializer::MtStakingMaterializer;
|
||||
/// Stable Token, ATA and Token-2022 account materializer.
|
||||
@@ -2250,22 +2252,28 @@ pub(crate) use self::materializer::MT_LIQUIDITY_ACCEPTED_FAMILIES;
|
||||
pub(crate) use self::materializer::MT_LIQUIDITY_COMPONENT_NAME;
|
||||
/// Crate-root access to `MT_LIQUIDITY_PROCESSOR_NAME`.
|
||||
pub(crate) use self::materializer::MT_LIQUIDITY_PROCESSOR_NAME;
|
||||
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES`.
|
||||
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
|
||||
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME;
|
||||
/// Crate-root access to `MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION`.
|
||||
pub(crate) use self::materializer::MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
|
||||
/// Crate-root access to `MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION`.
|
||||
pub(crate) use self::materializer::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
|
||||
/// Crate-root access to `MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES`.
|
||||
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
|
||||
/// Crate-root access to `MT_METADATA_TOKEN_2022_COMPONENT_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
|
||||
/// Crate-root access to `MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES`.
|
||||
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
|
||||
/// Crate-root access to `MT_METADATA_TOKEN_2022_PROCESSOR_NAME`.
|
||||
pub(crate) use self::materializer::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
|
||||
/// Crate-root access to `MT_METADATA_TOKEN_2022_PROJECTION_VERSION`.
|
||||
@@ -2406,8 +2414,8 @@ pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_FEES;
|
||||
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_LIFECYCLE;
|
||||
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA`.
|
||||
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
|
||||
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA`.
|
||||
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
|
||||
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM`.
|
||||
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
|
||||
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022`.
|
||||
pub(crate) use self::materializer::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022;
|
||||
/// Crate-root access to `TRACING_TARGET_MATERIALIZER_RISK`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/materializer.rs
|
||||
// version: 14
|
||||
// version: 15
|
||||
|
||||
//! Consolidated materializer modules.
|
||||
|
||||
@@ -73,10 +73,12 @@ pub use self::lending::MtLendingMaterializer;
|
||||
pub use self::lifecycle::MtLifecycleMaterializer;
|
||||
/// Reserved liquidity materializer.
|
||||
pub use self::liquidity::MtLiquidityMaterializer;
|
||||
/// Compatibility wrapper for the Solana Program Metadata materializer.
|
||||
pub use self::metadata::MtMetadataMaterializer;
|
||||
/// Stable Solana Program Metadata instruction materializer.
|
||||
pub use self::metadata::MtSolanaProgramMetadataMaterializer;
|
||||
/// Metaplex Token Metadata instruction materializer.
|
||||
pub use self::metadata::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
/// Solana Program Metadata instruction materializer.
|
||||
pub use self::metadata::MtMetadataSolanaProgramMaterializer;
|
||||
/// SPL Token-2022 embedded metadata and group instruction materializer.
|
||||
pub use self::metadata::MtMetadataToken2022Materializer;
|
||||
/// Materializes one canonical non-Metadata Metaplex account snapshot.
|
||||
pub use self::metadata::materializer_metadata_materialize_metaplex_account_snapshot;
|
||||
/// Materializes one canonical Metaplex Metadata account snapshot.
|
||||
@@ -272,30 +274,36 @@ pub(crate) use self::liquidity::MT_LIQUIDITY_ACCEPTED_FAMILIES;
|
||||
pub(crate) use self::liquidity::MT_LIQUIDITY_COMPONENT_NAME;
|
||||
/// Crate-visible `MT_LIQUIDITY_PROCESSOR_NAME` component constant.
|
||||
pub(crate) use self::liquidity::MT_LIQUIDITY_PROCESSOR_NAME;
|
||||
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
|
||||
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME;
|
||||
/// Crate-visible `MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
|
||||
/// Crate-visible `MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
|
||||
/// Crate-visible `MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
|
||||
/// Crate-visible `MT_METADATA_TOKEN_2022_COMPONENT_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
|
||||
/// Crate-visible `MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
|
||||
/// Crate-visible `MT_METADATA_TOKEN_2022_PROCESSOR_NAME` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
|
||||
/// Crate-visible `MT_METADATA_TOKEN_2022_PROJECTION_VERSION` component constant.
|
||||
pub(crate) use self::metadata::MT_METADATA_TOKEN_2022_PROJECTION_VERSION;
|
||||
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA` component constant.
|
||||
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
|
||||
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA` component constant.
|
||||
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
|
||||
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM` component constant.
|
||||
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
|
||||
/// Crate-visible `TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022` component constant.
|
||||
pub(crate) use self::metadata::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022;
|
||||
/// Crate-visible `MT_NFT_ACCEPTED_FAMILIES` component constant.
|
||||
@@ -491,10 +499,22 @@ mod tests {
|
||||
crate::MT_LIQUIDITY_PROCESSOR_NAME,
|
||||
),
|
||||
(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME,
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
|
||||
&crate::MtMetadataMetaplexTokenMetadataMaterializer,
|
||||
&crate::MtMetadataMetaplexTokenMetadataMaterializer,
|
||||
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
|
||||
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
|
||||
),
|
||||
(
|
||||
&crate::MtMetadataSolanaProgramMaterializer,
|
||||
&crate::MtMetadataSolanaProgramMaterializer,
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME,
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
|
||||
),
|
||||
(
|
||||
&crate::MtMetadataToken2022Materializer,
|
||||
&crate::MtMetadataToken2022Materializer,
|
||||
crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
|
||||
crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
|
||||
),
|
||||
(
|
||||
&crate::MtNftMaterializer,
|
||||
@@ -583,22 +603,6 @@ mod tests {
|
||||
];
|
||||
}
|
||||
|
||||
fn state_only_materializer_contracts() -> &'static [(&'static str, &'static str, &'static str)]
|
||||
{
|
||||
return &[
|
||||
(
|
||||
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
|
||||
crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
|
||||
crate::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA,
|
||||
),
|
||||
(
|
||||
crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
|
||||
crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
|
||||
crate::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_materializer_uses_the_component_and_processor_name_convention() {
|
||||
for (legacy, contextual, component_name, processor_name) in materializer_contracts() {
|
||||
@@ -615,18 +619,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_only_materializers_keep_runtime_processor_and_tracing_identity_aligned() {
|
||||
for (component_name, processor_name, tracing_target) in state_only_materializer_contracts()
|
||||
{
|
||||
assert_eq!(*tracing_target, *component_name);
|
||||
assert_eq!(
|
||||
component_name.strip_prefix("kb-lib."),
|
||||
std::option::Option::Some(*processor_name)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserved_materializers_are_empty_shells() {
|
||||
let materializers: &[&dyn crate::MtApiEventMaterializer] = &[
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/materializer/metadata.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
//! `metadata` materializer family.
|
||||
|
||||
@@ -7,23 +7,27 @@ mod metaplex_token_metadata;
|
||||
mod solana_program_metadata;
|
||||
mod token_2022;
|
||||
|
||||
/// Metaplex Token Metadata instruction materializer.
|
||||
pub use self::metaplex_token_metadata::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
/// Materializes one canonical non-Metadata Metaplex account snapshot.
|
||||
pub use self::metaplex_token_metadata::materializer_metadata_materialize_metaplex_account_snapshot;
|
||||
/// Materializes one canonical Metaplex Metadata account snapshot.
|
||||
pub use self::metaplex_token_metadata::materializer_metadata_materialize_metaplex_metadata_snapshot;
|
||||
/// Compatibility materializer retaining the historical generic metadata type name.
|
||||
pub use self::solana_program_metadata::MtMetadataMaterializer;
|
||||
/// Stable Solana Program Metadata instruction materializer.
|
||||
pub use self::solana_program_metadata::MtSolanaProgramMetadataMaterializer;
|
||||
/// Solana Program Metadata instruction materializer.
|
||||
pub use self::solana_program_metadata::MtMetadataSolanaProgramMaterializer;
|
||||
/// Materializes one decoded Solana Program Metadata account snapshot.
|
||||
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
|
||||
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
|
||||
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_buffer_snapshot;
|
||||
/// Materializes one bounded Solana Program Metadata Metadata account snapshot.
|
||||
pub use self::solana_program_metadata::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
|
||||
/// SPL Token-2022 embedded metadata and group instruction materializer.
|
||||
pub use self::token_2022::MtMetadataToken2022Materializer;
|
||||
/// Materializes Token-2022 embedded metadata and group snapshots.
|
||||
pub use self::token_2022::materializer_metadata_materialize_token_2022_snapshot;
|
||||
|
||||
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
|
||||
pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Metaplex Token Metadata projections.
|
||||
pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
|
||||
/// Stable processor name for Metaplex Token Metadata projections.
|
||||
@@ -33,17 +37,21 @@ pub(crate) use self::metaplex_token_metadata::MT_METADATA_METAPLEX_TOKEN_METADAT
|
||||
/// Canonical tracing target for Metaplex Token Metadata materialization.
|
||||
pub(crate) use self::metaplex_token_metadata::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA;
|
||||
/// Event families accepted by the Solana Program Metadata instruction materializer.
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Solana Program Metadata projections.
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
|
||||
/// Stable processor name for Solana Program Metadata projections.
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
|
||||
/// Stable projection schema version for Solana Program Metadata outputs.
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
|
||||
pub(crate) use self::solana_program_metadata::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
|
||||
/// Canonical tracing target for Solana Program Metadata materialization.
|
||||
pub(crate) use self::solana_program_metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
|
||||
pub(crate) use self::solana_program_metadata::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
|
||||
/// Event families accepted by the Token-2022 metadata instruction materializer.
|
||||
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Token-2022 embedded metadata projections.
|
||||
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
|
||||
/// Exact embedded Token Metadata and Token Group instruction ownership.
|
||||
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
|
||||
/// Stable processor name for Token-2022 embedded metadata projections.
|
||||
pub(crate) use self::token_2022::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
|
||||
/// Stable Token-2022 embedded metadata projection version.
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Metaplex Token Metadata account-state materializer.
|
||||
|
||||
mod account;
|
||||
mod constants;
|
||||
mod materializer;
|
||||
mod state;
|
||||
|
||||
/// Materializes one canonical non-Metadata Metaplex account snapshot.
|
||||
pub use self::account::materializer_metadata_materialize_metaplex_account_snapshot;
|
||||
/// Metaplex Token Metadata instruction materializer.
|
||||
pub use self::materializer::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
/// Materializes one canonical Metaplex Metadata account snapshot.
|
||||
pub use self::state::materializer_metadata_materialize_metaplex_metadata_snapshot;
|
||||
|
||||
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
|
||||
pub(crate) use self::constants::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Metaplex Token Metadata projections.
|
||||
pub(crate) use self::constants::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
|
||||
/// Stable processor name for Metaplex Token Metadata projections.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata/constants.rs
|
||||
// version: 4
|
||||
// version: 6
|
||||
|
||||
//! Local constants for the metadata metaplex_token_metadata materializer.
|
||||
|
||||
@@ -9,6 +9,9 @@ pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME: &str =
|
||||
/// Stable processor name persisted by metadata projections.
|
||||
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME: &str =
|
||||
"materializer.metadata.metaplex_token_metadata";
|
||||
/// Event families accepted by the Metaplex Token Metadata instruction materializer.
|
||||
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
|
||||
&[crate::MdEventFamily::Metadata];
|
||||
/// Stable projection contract version.
|
||||
pub(crate) const MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION: u32 = 2;
|
||||
/// Canonical tracing target for the metadata metaplex_token_metadata materializer.
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
// file: kb-lib/src/materializer/metadata/metaplex_token_metadata/materializer.rs
|
||||
// version: 1
|
||||
|
||||
//! Metaplex Token Metadata instruction materialization.
|
||||
|
||||
/// Metaplex Token Metadata instruction materializer.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
|
||||
impl crate::MtMaterializer for crate::MtMetadataMetaplexTokenMetadataMaterializer {
|
||||
fn materializer_name(&self) -> &'static str {
|
||||
return crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
fn materializer_version(&self) -> &'static str {
|
||||
return env!("CARGO_PKG_VERSION");
|
||||
}
|
||||
|
||||
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
|
||||
return event.event_family == crate::MdEventFamily::Metadata
|
||||
&& event.program_id.0 == kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
|
||||
&& event.surface_code.0 == crate::DC_METADATA_MTM_SURFACE_CODE
|
||||
&& instruction_contract(event.event_name.0.as_str()).is_some();
|
||||
}
|
||||
|
||||
fn materialize_event(
|
||||
&self,
|
||||
event: &crate::MdDecodedProtocolEvent,
|
||||
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
|
||||
if !crate::MtMaterializer::accepts_event(self, event) {
|
||||
return std::result::Result::Ok(std::vec::Vec::new());
|
||||
}
|
||||
return std::result::Result::Ok(std::vec![crate::MdMaterializedEvent {
|
||||
signature: event.signature.clone(),
|
||||
slot: event.slot,
|
||||
decoded_family: event.event_family,
|
||||
materialized_family: crate::MdMaterializedEventFamily::Metadata,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MtApiEventMaterializer for crate::MtMetadataMetaplexTokenMetadataMaterializer {
|
||||
fn identity(&self) -> crate::MtApiMaterializerIdentity {
|
||||
return crate::MtApiMaterializerIdentity {
|
||||
name: crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME.to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
|
||||
return crate::MT_METADATA_METAPLEX_TOKEN_METADATA_ACCEPTED_FAMILIES;
|
||||
}
|
||||
|
||||
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
return observation.event.event_family == crate::MdEventFamily::Metadata
|
||||
&& observation.event.program_id.0
|
||||
== kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID
|
||||
&& observation.event.surface_code.0 == crate::DC_METADATA_MTM_SURFACE_CODE
|
||||
&& instruction_contract(observation.event.event_name.0.as_str()).is_some()
|
||||
&& payload_contract_matches(observation);
|
||||
}
|
||||
|
||||
fn transaction_policy(
|
||||
&self,
|
||||
_family: crate::MdEventFamily,
|
||||
) -> crate::MtApiMaterializationTransactionPolicy {
|
||||
return crate::MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly;
|
||||
}
|
||||
|
||||
fn materialize(
|
||||
&self,
|
||||
observation: &crate::DcApiDecodedObservation,
|
||||
) -> crate::MtApiMaterializerExecutionResult {
|
||||
if !crate::MtApiEventMaterializer::accepts_observation(self, observation) {
|
||||
return crate::MtApiMaterializerExecutionResult::ignored();
|
||||
}
|
||||
if observation.transaction_failed || !observation.observation_committed {
|
||||
return crate::MtApiMaterializerExecutionResult::refused(
|
||||
"failed_transaction_metaplex_token_metadata_refused",
|
||||
"failed or uncommitted Metaplex Token Metadata instructions cannot create metadata outputs",
|
||||
);
|
||||
}
|
||||
let operation = observation.event.event_name.0.as_str();
|
||||
let (_, historical) = match instruction_contract(operation) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return crate::MtApiMaterializerExecutionResult::ignored(),
|
||||
};
|
||||
let deprecated = operation.starts_with("deprecated_");
|
||||
let output = crate::MtApiMaterializedOutput {
|
||||
output_key: format!(
|
||||
"metaplex_token_metadata_instruction:{}:{}:{}",
|
||||
observation.event.signature.0, observation.event.instruction_path.0, operation
|
||||
),
|
||||
family: crate::MdMaterializedEventFamily::Metadata,
|
||||
payload_json: serde_json::json!({
|
||||
"projectionVersion": crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROJECTION_VERSION,
|
||||
"domain": "metaplex_token_metadata",
|
||||
"projectionKind": "committed_instruction_fact",
|
||||
"projectionSemantics": "committed_instruction_fact_non_authoritative_state",
|
||||
"operation": operation,
|
||||
"programId": observation.event.program_id.0.clone(),
|
||||
"signature": observation.event.signature.0.clone(),
|
||||
"slot": observation.event.slot.0,
|
||||
"instructionPath": observation.event.instruction_path.0.clone(),
|
||||
"sourceKind": observation.event.source_kind,
|
||||
"transactionSucceeded": true,
|
||||
"historical": historical,
|
||||
"deprecated": deprecated,
|
||||
"authoritativeFinalStateCaptured": false,
|
||||
"stateProjectionAuthority": "post_execution_account_snapshot",
|
||||
"parameters": observation.payload_json.get("parameters").cloned().unwrap_or(serde_json::Value::Null),
|
||||
"accounts": observation.payload_json.get("accounts").cloned().unwrap_or(serde_json::Value::Null),
|
||||
"decodedPayload": observation.payload_json.clone(),
|
||||
"provenance": {
|
||||
"processorName": crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
|
||||
"processorVersion": env!("CARGO_PKG_VERSION"),
|
||||
"decoderProof": observation.proof.clone()
|
||||
}
|
||||
}),
|
||||
};
|
||||
tracing::debug!(
|
||||
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_METAPLEX_TOKEN_METADATA,
|
||||
component_name = crate::MT_METADATA_METAPLEX_TOKEN_METADATA_COMPONENT_NAME,
|
||||
processor_name = crate::MT_METADATA_METAPLEX_TOKEN_METADATA_PROCESSOR_NAME,
|
||||
action = "materialize_metaplex_token_metadata_instruction",
|
||||
operation = operation,
|
||||
historical = historical,
|
||||
deprecated = deprecated,
|
||||
signature = %observation.event.signature.0,
|
||||
instruction_path = %observation.event.instruction_path.0,
|
||||
output_count = 1_usize,
|
||||
"materialize committed Metaplex Token Metadata instruction"
|
||||
);
|
||||
return crate::MtApiMaterializerExecutionResult {
|
||||
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
|
||||
outputs: std::vec![output],
|
||||
diagnostics: std::vec::Vec::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn instruction_contract(operation: &str) -> std::option::Option<(u8, bool)> {
|
||||
return crate::DC_METADATA_MTM_INSTRUCTION_ENTRIES
|
||||
.iter()
|
||||
.find(|(_, code, _)| return *code == operation)
|
||||
.map(|(discriminator, _, historical)| return (*discriminator, *historical));
|
||||
}
|
||||
|
||||
fn payload_contract_matches(observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
let instruction =
|
||||
observation.payload_json.get("instruction").and_then(serde_json::Value::as_str);
|
||||
let program_id = observation.payload_json.get("programId").and_then(serde_json::Value::as_str);
|
||||
return instruction == std::option::Option::Some(observation.event.event_name.0.as_str())
|
||||
&& program_id
|
||||
== std::option::Option::Some(
|
||||
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn observation(operation: &str, committed: bool) -> crate::DcApiDecodedObservation {
|
||||
return crate::DcApiDecodedObservation {
|
||||
event_key: format!("metaplex_token_metadata:{operation}:0"),
|
||||
event: crate::MdDecodedProtocolEvent {
|
||||
signature: crate::MdSignature("signature111".to_string()),
|
||||
slot: crate::MdSlot(42),
|
||||
instruction_path: crate::MdInstructionPath("0".to_string()),
|
||||
program_id: crate::MdProgramId(
|
||||
kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID.to_string(),
|
||||
),
|
||||
protocol_code: crate::MdProtocolCode(
|
||||
crate::DC_METADATA_MTM_SURFACE_CODE.to_string(),
|
||||
),
|
||||
surface_code: crate::MdSurfaceCode(crate::DC_METADATA_MTM_SURFACE_CODE.to_string()),
|
||||
event_code: crate::MdEventCode(format!(
|
||||
"{}.{}",
|
||||
crate::DC_METADATA_MTM_SURFACE_CODE,
|
||||
operation
|
||||
)),
|
||||
event_name: crate::MdEventName(operation.to_string()),
|
||||
event_family: crate::MdEventFamily::Metadata,
|
||||
source_kind: crate::MdEventSourceKind::Instruction,
|
||||
confidence: crate::MdDecoderConfidence::ManualExact,
|
||||
},
|
||||
payload_json: serde_json::json!({
|
||||
"programId": kb_program_ids::METADATA_METAPLEX_TOKEN_METADATA_PROGRAM_ID,
|
||||
"instruction": operation,
|
||||
"parameters": {},
|
||||
"accounts": []
|
||||
}),
|
||||
transaction_failed: !committed,
|
||||
transaction_error: std::option::Option::None,
|
||||
observation_committed: committed,
|
||||
proof: crate::DcApiDecoderProof {
|
||||
kind: crate::DcApiDecoderProofKind::Manual,
|
||||
confidence: crate::MdDecoderConfidence::ManualExact,
|
||||
evidence: std::vec!["wire".to_string()],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_decoded_instruction_has_one_metadata_owner() {
|
||||
let materializer = crate::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
for (_, operation, historical) in crate::DC_METADATA_MTM_INSTRUCTION_ENTRIES.iter().copied()
|
||||
{
|
||||
let value = observation(operation, true);
|
||||
assert!(crate::MtApiEventMaterializer::accepts_observation(&materializer, &value));
|
||||
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
|
||||
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::Inserted);
|
||||
assert_eq!(result.outputs.len(), 1);
|
||||
assert_eq!(result.outputs[0].payload_json["operation"], operation);
|
||||
assert_eq!(result.outputs[0].payload_json["historical"], historical);
|
||||
assert_eq!(
|
||||
result.outputs[0].payload_json["deprecated"],
|
||||
operation.starts_with("deprecated_")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_and_foreign_observations_do_not_create_outputs() {
|
||||
let materializer = crate::MtMetadataMetaplexTokenMetadataMaterializer;
|
||||
let failed = observation("create_metadata_account_v3", false);
|
||||
let refused = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
|
||||
assert_eq!(refused.status, crate::MtApiMaterializerOutcomeStatus::Refused);
|
||||
let mut foreign = observation("create_metadata_account_v3", true);
|
||||
foreign.event.program_id =
|
||||
crate::MdProgramId(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID.to_string());
|
||||
let ignored = crate::MtApiEventMaterializer::materialize(&materializer, &foreign);
|
||||
assert_eq!(ignored.status, crate::MtApiMaterializerOutcomeStatus::Ignored);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/materializer/metadata/solana_program_metadata.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Solana Program Metadata materialization surface.
|
||||
|
||||
@@ -7,10 +7,8 @@ mod constants;
|
||||
mod materializer;
|
||||
mod state;
|
||||
|
||||
/// Compatibility materializer retaining the historical generic metadata type name.
|
||||
pub use self::materializer::MtMetadataMaterializer;
|
||||
/// Stable Solana Program Metadata instruction materializer.
|
||||
pub use self::materializer::MtSolanaProgramMetadataMaterializer;
|
||||
/// Solana Program Metadata instruction materializer.
|
||||
pub use self::materializer::MtMetadataSolanaProgramMaterializer;
|
||||
/// Materializes one decoded Solana Program Metadata account snapshot.
|
||||
pub use self::state::materializer_metadata_materialize_solana_program_metadata_account_snapshot;
|
||||
/// Materializes one bounded Solana Program Metadata Buffer account snapshot.
|
||||
@@ -19,12 +17,12 @@ pub use self::state::materializer_metadata_materialize_solana_program_metadata_b
|
||||
pub use self::state::materializer_metadata_materialize_solana_program_metadata_metadata_snapshot;
|
||||
|
||||
/// Event families accepted by the Solana Program Metadata instruction materializer.
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Solana Program Metadata projections.
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
|
||||
/// Stable processor name for Solana Program Metadata projections.
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME;
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME;
|
||||
/// Stable projection schema version for Solana Program Metadata outputs.
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION;
|
||||
pub(crate) use self::constants::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION;
|
||||
/// Canonical tracing target for Solana Program Metadata materialization.
|
||||
pub(crate) use self::constants::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA;
|
||||
pub(crate) use self::constants::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM;
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
//! Local constants for the Solana Program Metadata materializer.
|
||||
|
||||
/// Stable runtime component name for Solana Program Metadata materialization.
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME: &str =
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME: &str =
|
||||
"kb-lib.materializer.metadata.solana_program_metadata";
|
||||
/// Stable processor name persisted by Solana Program Metadata projections.
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME: &str =
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME: &str =
|
||||
"materializer.metadata.solana_program_metadata";
|
||||
/// Stable projection schema version for Solana Program Metadata outputs.
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION: u32 = 1;
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION: u32 = 1;
|
||||
pub(crate) const MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
|
||||
&[crate::MdEventFamily::Metadata];
|
||||
/// Canonical tracing target for Solana Program Metadata materialization.
|
||||
pub(crate) const TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA: &str =
|
||||
pub(crate) const TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM: &str =
|
||||
"kb-lib.materializer.metadata.solana_program_metadata";
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
// file: kb-lib/src/materializer/metadata/solana_program_metadata/materializer.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Committed Solana Program Metadata instruction projections.
|
||||
|
||||
/// Stable Solana Program Metadata instruction materializer.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MtSolanaProgramMetadataMaterializer;
|
||||
pub struct MtMetadataSolanaProgramMaterializer;
|
||||
|
||||
/// Compatibility materializer retaining the historical generic metadata type name.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MtMetadataMaterializer;
|
||||
|
||||
impl crate::MtMaterializer for crate::MtSolanaProgramMetadataMaterializer {
|
||||
impl crate::MtMaterializer for crate::MtMetadataSolanaProgramMaterializer {
|
||||
fn materializer_name(&self) -> &'static str {
|
||||
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
return crate::MT_METADATA_SOLANA_PROGRAM_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
fn materializer_version(&self) -> &'static str {
|
||||
@@ -45,84 +41,16 @@ impl crate::MtMaterializer for crate::MtSolanaProgramMetadataMaterializer {
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MtMaterializer for crate::MtMetadataMaterializer {
|
||||
fn materializer_name(&self) -> &'static str {
|
||||
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
fn materializer_version(&self) -> &'static str {
|
||||
return env!("CARGO_PKG_VERSION");
|
||||
}
|
||||
|
||||
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
|
||||
return crate::MtMaterializer::accepts_event(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
event,
|
||||
);
|
||||
}
|
||||
|
||||
fn materialize_event(
|
||||
&self,
|
||||
event: &crate::MdDecodedProtocolEvent,
|
||||
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
|
||||
return crate::MtMaterializer::materialize_event(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
event,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MtApiEventMaterializer for crate::MtMetadataMaterializer {
|
||||
fn identity(&self) -> crate::MtApiMaterializerIdentity {
|
||||
return crate::MtApiEventMaterializer::identity(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
);
|
||||
}
|
||||
|
||||
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
|
||||
return crate::MtApiEventMaterializer::accepted_families(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
);
|
||||
}
|
||||
|
||||
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
return crate::MtApiEventMaterializer::accepts_observation(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
observation,
|
||||
);
|
||||
}
|
||||
|
||||
fn transaction_policy(
|
||||
&self,
|
||||
family: crate::MdEventFamily,
|
||||
) -> crate::MtApiMaterializationTransactionPolicy {
|
||||
return crate::MtApiEventMaterializer::transaction_policy(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
family,
|
||||
);
|
||||
}
|
||||
|
||||
fn materialize(
|
||||
&self,
|
||||
observation: &crate::DcApiDecodedObservation,
|
||||
) -> crate::MtApiMaterializerExecutionResult {
|
||||
return crate::MtApiEventMaterializer::materialize(
|
||||
&crate::MtSolanaProgramMetadataMaterializer,
|
||||
observation,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterializer {
|
||||
impl crate::MtApiEventMaterializer for crate::MtMetadataSolanaProgramMaterializer {
|
||||
fn identity(&self) -> crate::MtApiMaterializerIdentity {
|
||||
return crate::MtApiMaterializerIdentity {
|
||||
name: crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME.to_string(),
|
||||
name: crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME.to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
|
||||
return crate::MT_METADATA_SOLANA_PROGRAM_METADATA_ACCEPTED_FAMILIES;
|
||||
return crate::MT_METADATA_SOLANA_PROGRAM_ACCEPTED_FAMILIES;
|
||||
}
|
||||
|
||||
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
@@ -165,7 +93,7 @@ impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterialize
|
||||
),
|
||||
family: crate::MdMaterializedEventFamily::Metadata,
|
||||
payload_json: serde_json::json!({
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
|
||||
"domain": "solana_program_metadata",
|
||||
"projectionKind": "committed_instruction_mutation",
|
||||
"projectionSemantics": "committed_instruction_fact_non_authoritative_state",
|
||||
@@ -183,14 +111,14 @@ impl crate::MtApiEventMaterializer for crate::MtSolanaProgramMetadataMaterialize
|
||||
"externalContentFetched": false,
|
||||
"externalAccountRead": false,
|
||||
"provenance": {
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
|
||||
"processorVersion": env!("CARGO_PKG_VERSION"),
|
||||
"decoderProof": observation.proof.clone()
|
||||
}
|
||||
}),
|
||||
};
|
||||
tracing::debug!(
|
||||
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM_METADATA,
|
||||
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_SOLANA_PROGRAM,
|
||||
action = "materialize_solana_program_metadata_instruction",
|
||||
operation = operation,
|
||||
signature = %observation.event.signature.0,
|
||||
@@ -355,9 +283,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn every_stable_instruction_has_one_materialized_mutation_fact() {
|
||||
let materializer = crate::MtSolanaProgramMetadataMaterializer;
|
||||
let materializer = crate::MtMetadataSolanaProgramMaterializer;
|
||||
let identity = crate::MtApiEventMaterializer::identity(&materializer);
|
||||
assert_eq!(identity.name, crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME);
|
||||
assert_eq!(identity.name, crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME);
|
||||
for (_, operation) in crate::DC_METADATA_SPM_INSTRUCTION_ENTRIES.iter().copied() {
|
||||
let value = observation(operation, true);
|
||||
assert!(crate::MtApiEventMaterializer::accepts_observation(&materializer, &value));
|
||||
@@ -369,14 +297,14 @@ mod tests {
|
||||
assert_eq!(result.outputs[0].payload_json["projection"]["replaced"], false);
|
||||
assert_eq!(
|
||||
result.outputs[0].payload_json["provenance"]["processorName"],
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME
|
||||
crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_instruction_is_refused_and_foreign_surface_is_ignored() {
|
||||
let materializer = crate::MtSolanaProgramMetadataMaterializer;
|
||||
let materializer = crate::MtMetadataSolanaProgramMaterializer;
|
||||
let failed = observation("set_data", false);
|
||||
let failure = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
|
||||
assert_eq!(failure.status, crate::MtApiMaterializerOutcomeStatus::Refused);
|
||||
@@ -424,7 +352,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn trim_keeps_prestable_alias_as_provenance_only() {
|
||||
let materializer = crate::MtSolanaProgramMetadataMaterializer;
|
||||
let materializer = crate::MtMetadataSolanaProgramMaterializer;
|
||||
let value = observation("trim", true);
|
||||
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
|
||||
assert_eq!(
|
||||
|
||||
@@ -63,7 +63,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_buffer_snapshot
|
||||
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
|
||||
family: crate::MdMaterializedEventFamily::Metadata,
|
||||
payload_json: serde_json::json!({
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
|
||||
"domain": "solana_program_metadata",
|
||||
"projectionKind": "buffer_state",
|
||||
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
|
||||
@@ -83,7 +83,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_buffer_snapshot
|
||||
"externalAccountRead": false,
|
||||
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
|
||||
"provenance": {
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
|
||||
"processorVersion": env!("CARGO_PKG_VERSION"),
|
||||
"source": "bounded_solana_program_metadata_account_decoder"
|
||||
}
|
||||
@@ -150,7 +150,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_metadata_snapsh
|
||||
output_key: format!("solana_program_metadata_account_state:{}", snapshot.account),
|
||||
family: crate::MdMaterializedEventFamily::Metadata,
|
||||
payload_json: serde_json::json!({
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROJECTION_VERSION,
|
||||
"projectionVersion": crate::MT_METADATA_SOLANA_PROGRAM_PROJECTION_VERSION,
|
||||
"domain": "solana_program_metadata",
|
||||
"projectionKind": "metadata_state",
|
||||
"projectionSemantics": "authoritative_bounded_owned_account_snapshot",
|
||||
@@ -177,7 +177,7 @@ pub fn materializer_metadata_materialize_solana_program_metadata_metadata_snapsh
|
||||
"externalAccountRead": false,
|
||||
"instructionProjectionRole": "mutation_observation_only_no_duplicate_state",
|
||||
"provenance": {
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_METADATA_PROCESSOR_NAME,
|
||||
"processorName": crate::MT_METADATA_SOLANA_PROGRAM_PROCESSOR_NAME,
|
||||
"processorVersion": env!("CARGO_PKG_VERSION"),
|
||||
"source": "bounded_solana_program_metadata_account_decoder"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
// file: kb-lib/src/materializer/metadata/token_2022.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Embedded SPL Token-2022 metadata materialization surface.
|
||||
|
||||
mod constants;
|
||||
mod materializer;
|
||||
mod state;
|
||||
|
||||
/// SPL Token-2022 embedded metadata and group instruction materializer.
|
||||
pub use self::materializer::MtMetadataToken2022Materializer;
|
||||
/// Materializes Token-2022 embedded metadata and group snapshots.
|
||||
pub use self::state::materializer_metadata_materialize_token_2022_snapshot;
|
||||
|
||||
/// Event families accepted by the Token-2022 metadata instruction materializer.
|
||||
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
|
||||
/// Stable runtime component name for Token-2022 embedded metadata projections.
|
||||
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
|
||||
/// Exact embedded Token Metadata and Token Group instruction ownership.
|
||||
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES;
|
||||
/// Stable processor name for Token-2022 embedded metadata projections.
|
||||
pub(crate) use self::constants::MT_METADATA_TOKEN_2022_PROCESSOR_NAME;
|
||||
/// Stable Token-2022 embedded metadata projection version.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/materializer/metadata/token_2022/constants.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Local constants for the metadata token_2022 materializer.
|
||||
|
||||
@@ -8,6 +8,21 @@ pub(crate) const MT_METADATA_TOKEN_2022_COMPONENT_NAME: &str =
|
||||
"kb-lib.materializer.metadata.token_2022";
|
||||
/// Stable processor name persisted by metadata projections.
|
||||
pub(crate) const MT_METADATA_TOKEN_2022_PROCESSOR_NAME: &str = "materializer.metadata.token_2022";
|
||||
/// Event families accepted by the Token-2022 metadata instruction materializer.
|
||||
pub(crate) const MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES: &[crate::MdEventFamily] =
|
||||
&[crate::MdEventFamily::Metadata];
|
||||
/// Exact embedded Token Metadata and Token Group instruction ownership.
|
||||
pub(crate) const MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES: &[&str] = &[
|
||||
"initialize_token_metadata",
|
||||
"update_token_metadata_field",
|
||||
"remove_token_metadata_key",
|
||||
"update_token_metadata_authority",
|
||||
"emit_token_metadata",
|
||||
"initialize_token_group",
|
||||
"update_token_group_max_size",
|
||||
"update_token_group_authority",
|
||||
"initialize_token_group_member",
|
||||
];
|
||||
/// Stable projection contract version.
|
||||
pub(crate) const MT_METADATA_TOKEN_2022_PROJECTION_VERSION: u32 = 2;
|
||||
/// Canonical tracing target for the metadata token_2022 materializer.
|
||||
|
||||
232
kb-lib/src/materializer/metadata/token_2022/materializer.rs
Normal file
232
kb-lib/src/materializer/metadata/token_2022/materializer.rs
Normal file
@@ -0,0 +1,232 @@
|
||||
// file: kb-lib/src/materializer/metadata/token_2022/materializer.rs
|
||||
// version: 1
|
||||
|
||||
//! SPL Token-2022 embedded metadata and group instruction materialization.
|
||||
|
||||
/// SPL Token-2022 embedded metadata and group instruction materializer.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MtMetadataToken2022Materializer;
|
||||
|
||||
impl crate::MtMaterializer for crate::MtMetadataToken2022Materializer {
|
||||
fn materializer_name(&self) -> &'static str {
|
||||
return crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME;
|
||||
}
|
||||
|
||||
fn materializer_version(&self) -> &'static str {
|
||||
return env!("CARGO_PKG_VERSION");
|
||||
}
|
||||
|
||||
fn accepts_event(&self, event: &crate::MdDecodedProtocolEvent) -> bool {
|
||||
return event.event_family == crate::MdEventFamily::Metadata
|
||||
&& event.program_id.0 == kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID
|
||||
&& event.surface_code.0 == crate::DC_SPL_TOKEN_2022_SURFACE_CODE
|
||||
&& crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES
|
||||
.iter()
|
||||
.any(|code| return *code == event.event_name.0.as_str());
|
||||
}
|
||||
|
||||
fn materialize_event(
|
||||
&self,
|
||||
event: &crate::MdDecodedProtocolEvent,
|
||||
) -> kb_core::Result<std::vec::Vec<crate::MdMaterializedEvent>> {
|
||||
if !crate::MtMaterializer::accepts_event(self, event) {
|
||||
return std::result::Result::Ok(std::vec::Vec::new());
|
||||
}
|
||||
return std::result::Result::Ok(std::vec![crate::MdMaterializedEvent {
|
||||
signature: event.signature.clone(),
|
||||
slot: event.slot,
|
||||
decoded_family: event.event_family,
|
||||
materialized_family: crate::MdMaterializedEventFamily::Metadata,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MtApiEventMaterializer for crate::MtMetadataToken2022Materializer {
|
||||
fn identity(&self) -> crate::MtApiMaterializerIdentity {
|
||||
return crate::MtApiMaterializerIdentity {
|
||||
name: crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME.to_string(),
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
fn accepted_families(&self) -> &'static [crate::MdEventFamily] {
|
||||
return crate::MT_METADATA_TOKEN_2022_ACCEPTED_FAMILIES;
|
||||
}
|
||||
|
||||
fn accepts_observation(&self, observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
return observation.event.event_family == crate::MdEventFamily::Metadata
|
||||
&& observation.event.program_id.0 == kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID
|
||||
&& observation.event.surface_code.0 == crate::DC_SPL_TOKEN_2022_SURFACE_CODE
|
||||
&& crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES
|
||||
.iter()
|
||||
.any(|code| return *code == observation.event.event_name.0.as_str())
|
||||
&& payload_contract_matches(observation);
|
||||
}
|
||||
|
||||
fn transaction_policy(
|
||||
&self,
|
||||
_family: crate::MdEventFamily,
|
||||
) -> crate::MtApiMaterializationTransactionPolicy {
|
||||
return crate::MtApiMaterializationTransactionPolicy::SuccessfulCommittedOnly;
|
||||
}
|
||||
|
||||
fn materialize(
|
||||
&self,
|
||||
observation: &crate::DcApiDecodedObservation,
|
||||
) -> crate::MtApiMaterializerExecutionResult {
|
||||
if !crate::MtApiEventMaterializer::accepts_observation(self, observation) {
|
||||
return crate::MtApiMaterializerExecutionResult::ignored();
|
||||
}
|
||||
if observation.transaction_failed || !observation.observation_committed {
|
||||
return crate::MtApiMaterializerExecutionResult::refused(
|
||||
"failed_transaction_token_2022_metadata_refused",
|
||||
"failed or uncommitted Token-2022 metadata instructions cannot create metadata outputs",
|
||||
);
|
||||
}
|
||||
let operation = observation.event.event_name.0.as_str();
|
||||
let output = crate::MtApiMaterializedOutput {
|
||||
output_key: format!(
|
||||
"token_2022_metadata_instruction:{}:{}:{}",
|
||||
observation.event.signature.0, observation.event.instruction_path.0, operation
|
||||
),
|
||||
family: crate::MdMaterializedEventFamily::Metadata,
|
||||
payload_json: serde_json::json!({
|
||||
"projectionVersion": crate::MT_METADATA_TOKEN_2022_PROJECTION_VERSION,
|
||||
"domain": "token_2022_metadata",
|
||||
"projectionKind": projection_kind(operation),
|
||||
"projectionSemantics": "committed_instruction_fact_non_authoritative_state",
|
||||
"operation": operation,
|
||||
"programId": observation.event.program_id.0.clone(),
|
||||
"signature": observation.event.signature.0.clone(),
|
||||
"slot": observation.event.slot.0,
|
||||
"instructionPath": observation.event.instruction_path.0.clone(),
|
||||
"sourceKind": observation.event.source_kind,
|
||||
"transactionSucceeded": true,
|
||||
"authoritativeFinalStateCaptured": false,
|
||||
"stateProjectionAuthority": "post_execution_token_2022_mint_snapshot",
|
||||
"parameters": observation.payload_json.get("parameters").cloned().unwrap_or(serde_json::Value::Null),
|
||||
"accounts": observation.payload_json.get("accounts").cloned().unwrap_or(serde_json::Value::Null),
|
||||
"authority": observation.payload_json.get("authority").cloned().unwrap_or(serde_json::Value::Null),
|
||||
"decodedPayload": observation.payload_json.clone(),
|
||||
"provenance": {
|
||||
"processorName": crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
|
||||
"processorVersion": env!("CARGO_PKG_VERSION"),
|
||||
"decoderProof": observation.proof.clone()
|
||||
}
|
||||
}),
|
||||
};
|
||||
tracing::debug!(
|
||||
target: crate::TRACING_TARGET_MATERIALIZER_METADATA_TOKEN_2022,
|
||||
component_name = crate::MT_METADATA_TOKEN_2022_COMPONENT_NAME,
|
||||
processor_name = crate::MT_METADATA_TOKEN_2022_PROCESSOR_NAME,
|
||||
action = "materialize_token_2022_metadata_instruction",
|
||||
operation = operation,
|
||||
signature = %observation.event.signature.0,
|
||||
instruction_path = %observation.event.instruction_path.0,
|
||||
output_count = 1_usize,
|
||||
"materialize committed Token-2022 metadata instruction"
|
||||
);
|
||||
return crate::MtApiMaterializerExecutionResult {
|
||||
status: crate::MtApiMaterializerOutcomeStatus::Inserted,
|
||||
outputs: std::vec![output],
|
||||
diagnostics: std::vec::Vec::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn payload_contract_matches(observation: &crate::DcApiDecodedObservation) -> bool {
|
||||
let instruction =
|
||||
observation.payload_json.get("instruction").and_then(serde_json::Value::as_str);
|
||||
let program_id = observation.payload_json.get("programId").and_then(serde_json::Value::as_str);
|
||||
return instruction == std::option::Option::Some(observation.event.event_name.0.as_str())
|
||||
&& program_id == std::option::Option::Some(kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID);
|
||||
}
|
||||
|
||||
fn projection_kind(operation: &str) -> &'static str {
|
||||
return match operation {
|
||||
"initialize_token_metadata" => "metadata_initialized",
|
||||
"update_token_metadata_field" => "metadata_field_updated",
|
||||
"remove_token_metadata_key" => "metadata_key_removed",
|
||||
"update_token_metadata_authority" => "metadata_authority_updated",
|
||||
"emit_token_metadata" => "metadata_emitted",
|
||||
"initialize_token_group" => "token_group_initialized",
|
||||
"update_token_group_max_size" => "token_group_max_size_updated",
|
||||
"update_token_group_authority" => "token_group_authority_updated",
|
||||
"initialize_token_group_member" => "token_group_member_initialized",
|
||||
_ => "unknown",
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn observation(operation: &str, committed: bool) -> crate::DcApiDecodedObservation {
|
||||
return crate::DcApiDecodedObservation {
|
||||
event_key: format!("token_2022:{operation}:0"),
|
||||
event: crate::MdDecodedProtocolEvent {
|
||||
signature: crate::MdSignature("signature111".to_string()),
|
||||
slot: crate::MdSlot(42),
|
||||
instruction_path: crate::MdInstructionPath("0".to_string()),
|
||||
program_id: crate::MdProgramId(
|
||||
kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID.to_string(),
|
||||
),
|
||||
protocol_code: crate::MdProtocolCode(
|
||||
crate::DC_SPL_TOKEN_2022_SURFACE_CODE.to_string(),
|
||||
),
|
||||
surface_code: crate::MdSurfaceCode(
|
||||
crate::DC_SPL_TOKEN_2022_SURFACE_CODE.to_string(),
|
||||
),
|
||||
event_code: crate::MdEventCode(format!(
|
||||
"{}.{}",
|
||||
crate::DC_SPL_TOKEN_2022_SURFACE_CODE,
|
||||
operation
|
||||
)),
|
||||
event_name: crate::MdEventName(operation.to_string()),
|
||||
event_family: crate::MdEventFamily::Metadata,
|
||||
source_kind: crate::MdEventSourceKind::Instruction,
|
||||
confidence: crate::MdDecoderConfidence::ManualExact,
|
||||
},
|
||||
payload_json: serde_json::json!({
|
||||
"programId": kb_program_ids::SPL_TOKEN_2022_PROGRAM_ID,
|
||||
"instruction": operation,
|
||||
"parameters": {},
|
||||
"accounts": [],
|
||||
"authority": null
|
||||
}),
|
||||
transaction_failed: !committed,
|
||||
transaction_error: std::option::Option::None,
|
||||
observation_committed: committed,
|
||||
proof: crate::DcApiDecoderProof {
|
||||
kind: crate::DcApiDecoderProofKind::Manual,
|
||||
confidence: crate::MdDecoderConfidence::ManualExact,
|
||||
evidence: std::vec!["wire".to_string()],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_embedded_metadata_and_group_instruction_has_one_owner() {
|
||||
let materializer = crate::MtMetadataToken2022Materializer;
|
||||
for operation in crate::MT_METADATA_TOKEN_2022_INSTRUCTION_ENTRIES {
|
||||
let value = observation(operation, true);
|
||||
assert!(crate::MtApiEventMaterializer::accepts_observation(&materializer, &value));
|
||||
let result = crate::MtApiEventMaterializer::materialize(&materializer, &value);
|
||||
assert_eq!(result.status, crate::MtApiMaterializerOutcomeStatus::Inserted);
|
||||
assert_eq!(result.outputs.len(), 1);
|
||||
assert_eq!(result.outputs[0].payload_json["operation"], *operation);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_and_non_metadata_observations_do_not_create_outputs() {
|
||||
let materializer = crate::MtMetadataToken2022Materializer;
|
||||
let failed = observation("initialize_token_metadata", false);
|
||||
let refused = crate::MtApiEventMaterializer::materialize(&materializer, &failed);
|
||||
assert_eq!(refused.status, crate::MtApiMaterializerOutcomeStatus::Refused);
|
||||
let mut unrelated = observation("initialize_token_metadata", true);
|
||||
unrelated.event.event_name = crate::MdEventName("transfer_checked".to_string());
|
||||
unrelated.payload_json["instruction"] =
|
||||
serde_json::Value::String("transfer_checked".to_string());
|
||||
let ignored = crate::MtApiEventMaterializer::materialize(&materializer, &unrelated);
|
||||
assert_eq!(ignored.status, crate::MtApiMaterializerOutcomeStatus::Ignored);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user