Skip to content

Commit

Permalink
[plerkle_serialization] Solana deserializers (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
kespinola authored Mar 5, 2024
1 parent 95ec22b commit 0bf3c81
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 5 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.

6 changes: 3 additions & 3 deletions 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"
version = "1.8.0"
authors = ["Metaplex Developers <dev@metaplex.com>"]
repository = "https://github.com/metaplex-foundation/digital-asset-validator-plugin"
license = "AGPL-3.0"
Expand All @@ -11,8 +11,8 @@ readme = "Readme.md"
[dependencies]
flatbuffers = "23.1.21"
chrono = "0.4.22"
serde = { version = "1.0.152"}
solana-sdk = { version = "~1.17"}
serde = { version = "1.0.152" }
solana-sdk = { version = "~1.17" }
solana-transaction-status = { version = "~1.17" }
bs58 = "0.4.0"
thiserror = "1.0.38"
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::*;
197 changes: 197 additions & 0 deletions plerkle_serialization/src/deserializer/solana.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use std::convert::TryFrom;

use crate::{
CompiledInnerInstructions as FBCompiledInnerInstructions,
CompiledInstruction as FBCompiledInstruction, InnerInstructions as FBInnerInstructions,
Pubkey as FBPubkey,
};
use flatbuffers::{ForwardsUOffset, Vector};
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, signature::Signature};
use solana_transaction_status::{InnerInstruction, InnerInstructions};

#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum SolanaDeserializerError {
#[error("Deserialization error")]
DeserializationError,
#[error("Not found")]
NotFound,
#[error("Invalid FlatBuffer key")]
InvalidFlatBufferKey,
}

pub type SolanaDeserializeResult<T> = Result<T, SolanaDeserializerError>;

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

fn try_from(pubkey: &FBPubkey) -> SolanaDeserializeResult<Self> {
Pubkey::try_from(pubkey.0.as_slice())
.map_err(|_error| SolanaDeserializerError::InvalidFlatBufferKey)
}
}

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

impl<'a> TryFrom<PlerkleOptionalU8Vector<'a>> for Vec<u8> {
type Error = SolanaDeserializerError;

fn try_from(data: PlerkleOptionalU8Vector<'a>) -> SolanaDeserializeResult<Self> {
Ok(data
.0
.ok_or(SolanaDeserializerError::NotFound)?
.bytes()
.to_vec())
}
}

pub struct PlerkleOptionalStr<'a>(pub Option<&'a str>);

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

fn try_from(data: PlerkleOptionalStr<'a>) -> SolanaDeserializeResult<Self> {
data.0
.ok_or(SolanaDeserializerError::NotFound)?
.parse::<Signature>()
.map_err(|_error| SolanaDeserializerError::DeserializationError)
}
}

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

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

fn try_from(public_keys: PlerkleOptionalPubkeyVector<'a>) -> SolanaDeserializeResult<Self> {
public_keys
.0
.ok_or(SolanaDeserializerError::NotFound)?
.iter()
.map(|key| {
Pubkey::try_from(key.0.as_slice())
.map_err(|_error| SolanaDeserializerError::InvalidFlatBufferKey)
})
.collect::<SolanaDeserializeResult<Vec<Pubkey>>>()
}
}

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

impl<'a> TryFrom<PlerkleCompiledInstructionVector<'a>> for Vec<CompiledInstruction> {
type Error = SolanaDeserializerError;

fn try_from(vec_cix: PlerkleCompiledInstructionVector<'a>) -> SolanaDeserializeResult<Self> {
let mut message_instructions = vec![];

for cix in vec_cix.0 {
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 PlerkleCompiledInnerInstructionVector<'a>(
pub Vector<'a, ForwardsUOffset<FBCompiledInnerInstructions<'a>>>,
);
impl<'a> TryFrom<PlerkleCompiledInnerInstructionVector<'a>> for Vec<InnerInstructions> {
type Error = SolanaDeserializerError;

fn try_from(
vec_ixs: PlerkleCompiledInnerInstructionVector<'a>,
) -> SolanaDeserializeResult<Self> {
let mut meta_inner_instructions = vec![];

for ixs in vec_ixs.0 {
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)
}
}

pub struct PlerkleInnerInstructionsVector<'a>(
pub Vector<'a, ForwardsUOffset<FBInnerInstructions<'a>>>,
);

impl<'a> TryFrom<PlerkleInnerInstructionsVector<'a>> for Vec<InnerInstructions> {
type Error = SolanaDeserializerError;

fn try_from(vec_ixs: PlerkleInnerInstructionsVector<'a>) -> SolanaDeserializeResult<Self> {
vec_ixs
.0
.iter()
.map(|iixs| {
let instructions = iixs
.instructions()
.ok_or(SolanaDeserializerError::NotFound)?
.iter()
.map(|cix| {
Ok(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(0),
})
})
.collect::<SolanaDeserializeResult<Vec<InnerInstruction>>>()?;
Ok(InnerInstructions {
index: iixs.index(),
instructions,
})
})
.collect::<SolanaDeserializeResult<Vec<InnerInstructions>>>()
}
}
3 changes: 2 additions & 1 deletion plerkle_serialization/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ mod slot_status_info_generated;
#[allow(unused_imports)]
mod transaction_info_generated;

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

0 comments on commit 0bf3c81

Please sign in to comment.