Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plerkle_serialization] Solana deserializers #70

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <[email protected]>"]
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