Skip to content

Commit

Permalink
feat: add deserializers for transforming plerkle structs into solana …
Browse files Browse the repository at this point in the history
…structs
  • Loading branch information
kespinola committed Feb 26, 2024
1 parent e4d05c7 commit 60581a3
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plerkle_serialization/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "plerkle_serialization"
description = "Metaplex Flatbuffers Plerkle Serialization for Geyser plugin producer/consumer patterns."
version = "1.6.0+solana.1.17.20"
version = "1.7.0+solana.1.17.20"
authors = ["Metaplex Developers <[email protected]>"]
repository = "https://github.com/metaplex-foundation/digital-asset-validator-plugin"
license = "AGPL-3.0"
Expand Down
3 changes: 3 additions & 0 deletions plerkle_serialization/src/deserializer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod solana;

pub use solana::*;
152 changes: 152 additions & 0 deletions plerkle_serialization/src/deserializer/solana.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use {
crate::{
CompiledInnerInstructions as FBCompiledInnerInstructions,
CompiledInstruction as FBCompiledInstruction, Pubkey as FBPubkey,
},
flatbuffers::{ForwardsUOffset, Vector},
solana_sdk::{
instruction::CompiledInstruction,
pubkey::Pubkey,
signature::{ParseSignatureError, Signature},
},
solana_transaction_status::{InnerInstruction, InnerInstructions},
};

#[derive(Debug, thiserror::Error)]
pub enum SolanaDeserializerError {
#[error("solana pubkey deserialization error")]
Pubkey,
#[error("solana signature deserialization error")]
Signature,
#[error("expected data not found in FlatBuffer")]
NotFound,
}

impl TryFrom<&FBPubkey> for Pubkey {
type Error = SolanaDeserializerError;

fn try_from(value: &FBPubkey) -> Result<Self, Self::Error> {
Pubkey::try_from(value.0.as_slice()).map_err(|_| SolanaDeserializerError::Pubkey)
}
}

impl TryFrom<FBPubkey> for Pubkey {
type Error = SolanaDeserializerError;

fn try_from(value: FBPubkey) -> Result<Self, Self::Error> {
Pubkey::try_from(value.0).map_err(|_| SolanaDeserializerError::Pubkey)
}
}

pub struct OptionalU8Vector<'a>(Option<Vector<'a, u8>>);

impl<'a> TryFrom<OptionalU8Vector<'a>> for &'a [u8] {
type Error = SolanaDeserializerError;

fn try_from(value: OptionalU8Vector<'a>) -> Result<Self, Self::Error> {
value
.0
.map(|data| data.bytes())
.ok_or(SolanaDeserializerError::NotFound)
}
}

struct OptionalStr<'a>(Option<&'a str>);

impl<'a> TryFrom<OptionalStr<'a>> for Signature {
type Error = SolanaDeserializerError;

fn try_from(value: OptionalStr<'a>) -> Result<Self, Self::Error> {
value
.0
.ok_or(ParseSignatureError::Invalid)
.and_then(|data| data.parse())
.map_err(|_| SolanaDeserializerError::Signature)
}
}

pub struct OptionalPubkeyVector<'a>(Option<Vector<'a, FBPubkey>>);

impl<'a> TryFrom<OptionalPubkeyVector<'a>> for Vec<Pubkey> {
type Error = SolanaDeserializerError;

fn try_from(value: OptionalPubkeyVector<'a>) -> Result<Self, Self::Error> {
let mut account_keys = vec![];
for key in value.0.ok_or(SolanaDeserializerError::Pubkey)? {
account_keys.push(Pubkey::try_from(key)?);
}
Ok(account_keys)
}
}

pub struct OptionalCompiledInstructionVector<'a>(
Option<Vector<'a, ForwardsUOffset<FBCompiledInstruction<'a>>>>,
);

impl TryFrom<OptionalCompiledInstructionVector<'_>> for Vec<CompiledInstruction> {
type Error = SolanaDeserializerError;

fn try_from(value: OptionalCompiledInstructionVector<'_>) -> Result<Self, Self::Error> {
let mut message_instructions = vec![];
for cix in value.0.ok_or(SolanaDeserializerError::NotFound)? {
message_instructions.push(CompiledInstruction {
program_id_index: cix.program_id_index(),
accounts: cix
.accounts()
.ok_or(SolanaDeserializerError::NotFound)?
.bytes()
.to_vec(),
data: cix
.data()
.ok_or(SolanaDeserializerError::NotFound)?
.bytes()
.to_vec(),
})
}
Ok(message_instructions)
}
}

pub struct OptionalCompiledInnerInstructionsVector<'a>(
Option<Vector<'a, ForwardsUOffset<FBCompiledInnerInstructions<'a>>>>,
);

impl TryFrom<OptionalCompiledInnerInstructionsVector<'_>> for Vec<InnerInstructions> {
type Error = SolanaDeserializerError;

fn try_from(value: OptionalCompiledInnerInstructionsVector<'_>) -> Result<Self, Self::Error> {
let mut meta_inner_instructions = vec![];
for ixs in value.0.ok_or(SolanaDeserializerError::NotFound)? {
let mut instructions = vec![];
for ix in ixs
.instructions()
.ok_or(SolanaDeserializerError::NotFound)?
{
let cix = ix
.compiled_instruction()
.ok_or(SolanaDeserializerError::NotFound)?;
instructions.push(InnerInstruction {
instruction: CompiledInstruction {
program_id_index: cix.program_id_index(),
accounts: cix
.accounts()
.ok_or(SolanaDeserializerError::NotFound)?
.bytes()
.to_vec(),
data: cix
.data()
.ok_or(SolanaDeserializerError::NotFound)?
.bytes()
.to_vec(),
},
stack_height: Some(ix.stack_height() as u32),
});
}
meta_inner_instructions.push(InnerInstructions {
index: ixs.index(),
instructions,
})
}
Ok(meta_inner_instructions)
}
}
1 change: 1 addition & 0 deletions plerkle_serialization/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod slot_status_info_generated;
#[allow(unused_imports)]
mod transaction_info_generated;

pub mod deserializer;
pub mod error;
pub mod serializer;
pub use account_info_generated::*;
Expand Down

0 comments on commit 60581a3

Please sign in to comment.