From fc2bf2d3b669d1c6655ae48b0a05f470938f3676 Mon Sep 17 00:00:00 2001 From: Jack May Date: Fri, 17 Sep 2021 11:36:57 -0700 Subject: [PATCH] Cleanup and standardize precompiles (#19918) --- programs/bpf/tests/programs.rs | 2 +- sdk/src/ed25519_instruction.rs | 93 ++++++++++++------------ sdk/src/lib.rs | 1 + sdk/src/precompiles.rs | 117 +++++++++++++++++++++++++++++++ sdk/src/secp256k1_instruction.rs | 112 +++++++++++++++++------------ sdk/src/transaction/mod.rs | 40 +++-------- sdk/src/transaction/sanitized.rs | 41 +++-------- 7 files changed, 250 insertions(+), 156 deletions(-) create mode 100644 sdk/src/precompiles.rs diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 1f3f82a047..b73c284ebd 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1090,7 +1090,7 @@ fn test_program_bpf_invoke_sanity() { result.unwrap_err(), TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete) ); - } + } } #[cfg(feature = "bpf_rust")] diff --git a/sdk/src/ed25519_instruction.rs b/sdk/src/ed25519_instruction.rs index b8e814e3e4..704b210cbb 100644 --- a/sdk/src/ed25519_instruction.rs +++ b/sdk/src/ed25519_instruction.rs @@ -1,27 +1,9 @@ #![cfg(feature = "full")] -use crate::{decode_error::DecodeError, instruction::Instruction}; +use crate::{feature_set::FeatureSet, instruction::Instruction, precompiles::PrecompileError}; use bytemuck::{bytes_of, Pod, Zeroable}; use ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier}; -use thiserror::Error; - -#[derive(Error, Debug, Clone, PartialEq)] -pub enum Ed25519Error { - #[error("ed25519 public key is not valid")] - InvalidPublicKey, - #[error("ed25519 signature is not valid")] - InvalidSignature, - #[error("offset not valid")] - InvalidDataOffsets, - #[error("instruction is incorrect size")] - InvalidInstructionDataSize, -} - -impl DecodeError for Ed25519Error { - fn type_of() -> &'static str { - "Ed25519Error" - } -} +use std::sync::Arc; pub const PUBKEY_SERIALIZED_SIZE: usize = 32; pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; @@ -95,19 +77,23 @@ pub fn new_ed25519_instruction(keypair: &ed25519_dalek::Keypair, message: &[u8]) } } -pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(), Ed25519Error> { +pub fn verify( + data: &[u8], + instruction_datas: &[&[u8]], + _feature_set: &Arc, +) -> Result<(), PrecompileError> { if data.len() < SIGNATURE_OFFSETS_START { - return Err(Ed25519Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } let num_signatures = data[0] as usize; if num_signatures == 0 && data.len() > SIGNATURE_OFFSETS_START { - return Err(Ed25519Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } let expected_data_size = num_signatures .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) .saturating_add(SIGNATURE_OFFSETS_START); if data.len() < expected_data_size { - return Err(Ed25519Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } for i in 0..num_signatures { let start = i @@ -117,23 +103,23 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(), // bytemuck wants structures aligned let offsets: &Ed25519SignatureOffsets = bytemuck::try_from_bytes(&data[start..end]) - .map_err(|_| Ed25519Error::InvalidDataOffsets)?; + .map_err(|_| PrecompileError::InvalidDataOffsets)?; // Parse out signature let signature_index = offsets.signature_instruction_index as usize; if signature_index >= instruction_datas.len() { - return Err(Ed25519Error::InvalidDataOffsets); + return Err(PrecompileError::InvalidDataOffsets); } let signature_instruction = instruction_datas[signature_index]; let sig_start = offsets.signature_offset as usize; let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE); if sig_end >= signature_instruction.len() { - return Err(Ed25519Error::InvalidDataOffsets); + return Err(PrecompileError::InvalidDataOffsets); } let signature = ed25519_dalek::Signature::from_bytes(&signature_instruction[sig_start..sig_end]) - .map_err(|_| Ed25519Error::InvalidSignature)?; + .map_err(|_| PrecompileError::InvalidSignature)?; // Parse out pubkey let pubkey = get_data_slice( @@ -144,7 +130,7 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(), )?; let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey) - .map_err(|_| Ed25519Error::InvalidPublicKey)?; + .map_err(|_| PrecompileError::InvalidPublicKey)?; // Parse out message let message = get_data_slice( @@ -156,7 +142,7 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(), publickey .verify(message, &signature) - .map_err(|_| Ed25519Error::InvalidSignature)?; + .map_err(|_| PrecompileError::InvalidSignature)?; } Ok(()) } @@ -166,16 +152,16 @@ fn get_data_slice<'a>( instruction_index: u16, offset_start: u16, size: usize, -) -> Result<&'a [u8], Ed25519Error> { +) -> Result<&'a [u8], PrecompileError> { let signature_index = instruction_index as usize; if signature_index >= instruction_datas.len() { - return Err(Ed25519Error::InvalidDataOffsets); + return Err(PrecompileError::InvalidDataOffsets); } let signature_instruction = &instruction_datas[signature_index]; let start = offset_start as usize; let end = start.saturating_add(size); if end > signature_instruction.len() { - return Err(Ed25519Error::InvalidDataOffsets); + return Err(PrecompileError::InvalidDataOffsets); } Ok(&instruction_datas[signature_index][start..end]) @@ -188,7 +174,7 @@ pub mod test { fn test_case( num_signatures: u16, offsets: &Ed25519SignatureOffsets, - ) -> Result<(), Ed25519Error> { + ) -> Result<(), PrecompileError> { assert_eq!( bytemuck::bytes_of(offsets).len(), SIGNATURE_OFFSETS_SERIALIZED_SIZE @@ -198,7 +184,11 @@ pub mod test { instruction_data[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures)); instruction_data[SIGNATURE_OFFSETS_START..DATA_START].copy_from_slice(bytes_of(offsets)); - verify_signatures(&instruction_data, &[&[0u8; 100]]) + verify( + &instruction_data, + &[&[0u8; 100]], + &Arc::new(FeatureSet::all_enabled()), + ) } #[test] @@ -212,8 +202,12 @@ pub mod test { instruction_data.truncate(instruction_data.len() - 1); assert_eq!( - verify_signatures(&instruction_data, &[&[0u8; 100]]), - Err(Ed25519Error::InvalidInstructionDataSize) + verify( + &instruction_data, + &[&[0u8; 100]], + &Arc::new(FeatureSet::all_enabled()), + ), + Err(PrecompileError::InvalidInstructionDataSize) ); let offsets = Ed25519SignatureOffsets { @@ -222,7 +216,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -231,7 +225,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -240,7 +234,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); } @@ -251,7 +245,10 @@ pub mod test { message_data_size: 1, ..Ed25519SignatureOffsets::default() }; - assert_eq!(test_case(1, &offsets), Err(Ed25519Error::InvalidSignature)); + assert_eq!( + test_case(1, &offsets), + Err(PrecompileError::InvalidSignature) + ); let offsets = Ed25519SignatureOffsets { message_data_offset: 100, @@ -260,7 +257,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -270,7 +267,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -280,7 +277,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); } @@ -292,7 +289,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -301,7 +298,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); } @@ -313,7 +310,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = Ed25519SignatureOffsets { @@ -322,7 +319,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Ed25519Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); } } diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index cb2558587a..c5a3436dc8 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -36,6 +36,7 @@ pub mod nonce_account; pub mod nonce_keyed_account; pub mod packet; pub mod poh_config; +pub mod precompiles; pub mod process_instruction; pub mod program_utils; pub mod pubkey; diff --git a/sdk/src/precompiles.rs b/sdk/src/precompiles.rs new file mode 100644 index 0000000000..3372fca3c4 --- /dev/null +++ b/sdk/src/precompiles.rs @@ -0,0 +1,117 @@ +//! @brief Solana precompiled programs + +#![cfg(feature = "full")] + +use { + crate::{ + decode_error::DecodeError, + feature_set::{ed25519_program_enabled, FeatureSet}, + instruction::CompiledInstruction, + pubkey::Pubkey, + }, + lazy_static::lazy_static, + std::sync::Arc, + thiserror::Error, +}; + +/// Precompile errors +#[derive(Error, Debug, Clone, PartialEq)] +pub enum PrecompileError { + #[error("public key is not valid")] + InvalidPublicKey, + #[error("id is not valid")] + InvalidRecoveryId, + #[error("signature is not valid")] + InvalidSignature, + #[error("offset not valid")] + InvalidDataOffsets, + #[error("instruction is incorrect size")] + InvalidInstructionDataSize, +} +impl DecodeError for PrecompileError { + fn type_of() -> &'static str { + "PrecompileError" + } +} + +/// All precompiled programs must implement the `Verify` function +pub type Verify = fn(&[u8], &[&[u8]], &Arc) -> std::result::Result<(), PrecompileError>; + +/// Information on a precompiled program +struct Precompile { + /// Program id + pub program_id: Pubkey, + /// Feature to enable on, `None` indicates always enabled + pub feature: Option, + /// Verification function + pub verify_fn: Verify, +} +impl Precompile { + /// Creates a new `Precompile` + pub fn new(program_id: Pubkey, feature: Option, verify_fn: Verify) -> Self { + Precompile { + program_id, + feature, + verify_fn, + } + } + /// Check if a program id is this precompiled program + pub fn check_id(&self, program_id: &Pubkey, feature_set: &Arc) -> bool { + self.feature.map_or(true, |f| feature_set.is_active(&f)) && self.program_id == *program_id + } + /// Verify this precompiled program + pub fn verify( + &self, + data: &[u8], + instruction_datas: &[&[u8]], + feature_set: &Arc, + ) -> std::result::Result<(), PrecompileError> { + (self.verify_fn)(data, instruction_datas, feature_set) + } +} + +lazy_static! { + /// The list of all precompiled programs + static ref PRECOMPILES: Vec = vec![ + Precompile::new( + crate::secp256k1_program::id(), + None, + crate::secp256k1_instruction::verify, + ), + Precompile::new( + crate::ed25519_program::id(), + Some(ed25519_program_enabled::id()), + crate::ed25519_instruction::verify, + ), + ]; +} + +/// Check if a program is a precompiled program +pub fn is_precompile(program_id: &Pubkey, feature_set: &Arc) -> bool { + PRECOMPILES + .iter() + .any(|precompile| precompile.check_id(program_id, feature_set)) +} + +/// Check that a program is precompiled and if so verify it +pub fn verify_if_precompile( + program_id: &Pubkey, + precompile_instruction: &CompiledInstruction, + all_instructions: &[CompiledInstruction], + feature_set: &Arc, +) -> Result<(), PrecompileError> { + for precompile in PRECOMPILES.iter() { + if precompile.check_id(program_id, feature_set) { + let instruction_datas: Vec<_> = all_instructions + .iter() + .map(|instruction| instruction.data.as_ref()) + .collect(); + return precompile.verify( + &precompile_instruction.data, + &instruction_datas, + feature_set, + ); + } + } + Ok(()) +} diff --git a/sdk/src/secp256k1_instruction.rs b/sdk/src/secp256k1_instruction.rs index b60b9c6103..299237b9cb 100644 --- a/sdk/src/secp256k1_instruction.rs +++ b/sdk/src/secp256k1_instruction.rs @@ -1,16 +1,13 @@ #![cfg(feature = "full")] -use crate::instruction::Instruction; +use crate::{ + feature_set::{libsecp256k1_0_5_upgrade_enabled, libsecp256k1_fail_on_bad_count, FeatureSet}, + instruction::Instruction, + precompiles::PrecompileError, +}; use digest::Digest; use serde_derive::{Deserialize, Serialize}; - -#[derive(Debug, PartialEq)] -pub enum Secp256k1Error { - InvalidSignature, - InvalidRecoveryId, - InvalidDataOffsets, - InvalidInstructionDataSize, -} +use std::sync::Arc; pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20; pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; @@ -99,27 +96,27 @@ pub fn construct_eth_pubkey( addr } -pub fn verify_eth_addresses( +pub fn verify( data: &[u8], instruction_datas: &[&[u8]], - libsecp256k1_0_5_upgrade_enabled: bool, - libsecp256k1_fail_on_bad_count: bool, -) -> Result<(), Secp256k1Error> { + feature_set: &Arc, +) -> Result<(), PrecompileError> { if data.is_empty() { - return Err(Secp256k1Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } let count = data[0] as usize; - if libsecp256k1_fail_on_bad_count && count == 0 && data.len() > 1 { + if feature_set.is_active(&libsecp256k1_fail_on_bad_count::id()) && count == 0 && data.len() > 1 + { // count is zero but the instruction data indicates that is probably not // correct, fail the instruction to catch probable invalid secp256k1 // instruction construction. - return Err(Secp256k1Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } let expected_data_size = count .saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE) .saturating_add(1); if data.len() < expected_data_size { - return Err(Secp256k1Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } for i in 0..count { let start = i @@ -128,21 +125,21 @@ pub fn verify_eth_addresses( let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE); let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end]) - .map_err(|_| Secp256k1Error::InvalidSignature)?; + .map_err(|_| PrecompileError::InvalidSignature)?; // Parse out signature let signature_index = offsets.signature_instruction_index as usize; if signature_index >= instruction_datas.len() { - return Err(Secp256k1Error::InvalidInstructionDataSize); + return Err(PrecompileError::InvalidInstructionDataSize); } let signature_instruction = instruction_datas[signature_index]; let sig_start = offsets.signature_offset as usize; let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE); if sig_end >= signature_instruction.len() { - return Err(Secp256k1Error::InvalidSignature); + return Err(PrecompileError::InvalidSignature); } - let sig_parse_result = if libsecp256k1_0_5_upgrade_enabled { + let sig_parse_result = if feature_set.is_active(&libsecp256k1_0_5_upgrade_enabled::id()) { libsecp256k1::Signature::parse_standard_slice( &signature_instruction[sig_start..sig_end], ) @@ -152,10 +149,10 @@ pub fn verify_eth_addresses( ) }; - let signature = sig_parse_result.map_err(|_| Secp256k1Error::InvalidSignature)?; + let signature = sig_parse_result.map_err(|_| PrecompileError::InvalidSignature)?; let recovery_id = libsecp256k1::RecoveryId::parse(signature_instruction[sig_end]) - .map_err(|_| Secp256k1Error::InvalidRecoveryId)?; + .map_err(|_| PrecompileError::InvalidRecoveryId)?; // Parse out pubkey let eth_address_slice = get_data_slice( @@ -182,11 +179,11 @@ pub fn verify_eth_addresses( &signature, &recovery_id, ) - .map_err(|_| Secp256k1Error::InvalidSignature)?; + .map_err(|_| PrecompileError::InvalidSignature)?; let eth_address = construct_eth_pubkey(&pubkey); if eth_address_slice != eth_address { - return Err(Secp256k1Error::InvalidSignature); + return Err(PrecompileError::InvalidSignature); } } Ok(()) @@ -197,16 +194,16 @@ fn get_data_slice<'a>( instruction_index: u8, offset_start: u16, size: usize, -) -> Result<&'a [u8], Secp256k1Error> { +) -> Result<&'a [u8], PrecompileError> { let signature_index = instruction_index as usize; if signature_index >= instruction_datas.len() { - return Err(Secp256k1Error::InvalidDataOffsets); + return Err(PrecompileError::InvalidDataOffsets); } let signature_instruction = &instruction_datas[signature_index]; let start = offset_start as usize; let end = start.saturating_add(size); if end > signature_instruction.len() { - return Err(Secp256k1Error::InvalidSignature); + return Err(PrecompileError::InvalidSignature); } Ok(&instruction_datas[signature_index][start..end]) @@ -216,13 +213,23 @@ fn get_data_slice<'a>( pub mod test { use super::*; - fn test_case(num_signatures: u8, offsets: &SecpSignatureOffsets) -> Result<(), Secp256k1Error> { + fn test_case( + num_signatures: u8, + offsets: &SecpSignatureOffsets, + ) -> Result<(), PrecompileError> { let mut instruction_data = vec![0u8; DATA_START]; instruction_data[0] = num_signatures; let writer = std::io::Cursor::new(&mut instruction_data[1..]); bincode::serialize_into(writer, &offsets).unwrap(); + let mut feature_set = FeatureSet::all_enabled(); + feature_set + .active + .remove(&libsecp256k1_0_5_upgrade_enabled::id()); + feature_set + .inactive + .insert(libsecp256k1_0_5_upgrade_enabled::id()); - verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true) + verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)) } #[test] @@ -235,10 +242,17 @@ pub mod test { let writer = std::io::Cursor::new(&mut instruction_data[1..]); bincode::serialize_into(writer, &offsets).unwrap(); instruction_data.truncate(instruction_data.len() - 1); + let mut feature_set = FeatureSet::all_enabled(); + feature_set + .active + .remove(&libsecp256k1_0_5_upgrade_enabled::id()); + feature_set + .inactive + .insert(libsecp256k1_0_5_upgrade_enabled::id()); assert_eq!( - verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true), - Err(Secp256k1Error::InvalidInstructionDataSize) + verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)), + Err(PrecompileError::InvalidInstructionDataSize) ); let offsets = SecpSignatureOffsets { @@ -247,7 +261,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidInstructionDataSize) + Err(PrecompileError::InvalidInstructionDataSize) ); let offsets = SecpSignatureOffsets { @@ -256,7 +270,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); let offsets = SecpSignatureOffsets { @@ -265,7 +279,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidDataOffsets) + Err(PrecompileError::InvalidDataOffsets) ); } @@ -278,7 +292,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); let offsets = SecpSignatureOffsets { @@ -288,7 +302,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); let offsets = SecpSignatureOffsets { @@ -298,7 +312,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); let offsets = SecpSignatureOffsets { @@ -308,7 +322,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); } @@ -320,7 +334,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); let offsets = SecpSignatureOffsets { @@ -329,7 +343,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); } @@ -341,7 +355,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); let offsets = SecpSignatureOffsets { @@ -350,7 +364,7 @@ pub mod test { }; assert_eq!( test_case(1, &offsets), - Err(Secp256k1Error::InvalidSignature) + Err(PrecompileError::InvalidSignature) ); } @@ -363,9 +377,17 @@ pub mod test { instruction_data[0] = 0; let writer = std::io::Cursor::new(&mut instruction_data[1..]); bincode::serialize_into(writer, &offsets).unwrap(); + let mut feature_set = FeatureSet::all_enabled(); + feature_set + .active + .remove(&libsecp256k1_0_5_upgrade_enabled::id()); + feature_set + .inactive + .insert(libsecp256k1_0_5_upgrade_enabled::id()); + assert_eq!( - verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true), - Err(Secp256k1Error::InvalidInstructionDataSize) + verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)), + Err(PrecompileError::InvalidInstructionDataSize) ); } } diff --git a/sdk/src/transaction/mod.rs b/sdk/src/transaction/mod.rs index a0354c7510..54ee2d21d1 100644 --- a/sdk/src/transaction/mod.rs +++ b/sdk/src/transaction/mod.rs @@ -4,15 +4,14 @@ use { crate::{ - ed25519_instruction::verify_signatures, hash::Hash, instruction::{CompiledInstruction, Instruction, InstructionError}, message::{Message, SanitizeMessageError}, nonce::NONCED_TX_MARKER_IX_INDEX, + precompiles::verify_if_precompile, program_utils::limited_deserialize, pubkey::Pubkey, sanitize::{Sanitize, SanitizeError}, - secp256k1_instruction::verify_eth_addresses, short_vec, signature::{Signature, SignerError}, signers::Signers, @@ -433,6 +432,7 @@ impl Transaction { .collect() } + /// Verify the precompiled programs in this transaction pub fn verify_precompiles(&self, feature_set: &Arc) -> Result<()> { for instruction in &self.message().instructions { // The Transaction may not be sanitized at this point @@ -440,34 +440,14 @@ impl Transaction { return Err(TransactionError::AccountNotFound); } let program_id = &self.message().account_keys[instruction.program_id_index as usize]; - if crate::secp256k1_program::check_id(program_id) { - let instruction_datas: Vec<_> = self - .message() - .instructions - .iter() - .map(|instruction| instruction.data.as_ref()) - .collect(); - let data = &instruction.data; - let e = verify_eth_addresses( - data, - &instruction_datas, - feature_set.is_active(&feature_set::libsecp256k1_0_5_upgrade_enabled::id()), - feature_set.is_active(&feature_set::libsecp256k1_fail_on_bad_count::id()), - ); - e.map_err(|_| TransactionError::InvalidAccountIndex)?; - } else if crate::ed25519_program::check_id(program_id) - && feature_set.is_active(&feature_set::ed25519_program_enabled::id()) - { - let instruction_datas: Vec<_> = self - .message() - .instructions - .iter() - .map(|instruction| instruction.data.as_ref()) - .collect(); - let data = &instruction.data; - let e = verify_signatures(data, &instruction_datas); - e.map_err(|_| TransactionError::InvalidAccountIndex)?; - } + + verify_if_precompile( + program_id, + instruction, + &self.message().instructions, + feature_set, + ) + .map_err(|_| TransactionError::InvalidAccountIndex)?; } Ok(()) } diff --git a/sdk/src/transaction/sanitized.rs b/sdk/src/transaction/sanitized.rs index e638a46240..dfa128ba0c 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/src/transaction/sanitized.rs @@ -2,15 +2,13 @@ use { crate::{ - ed25519_instruction::verify_signatures, hash::Hash, message::{v0, MappedAddresses, MappedMessage, SanitizedMessage, VersionedMessage}, nonce::NONCED_TX_MARKER_IX_INDEX, + precompiles::verify_if_precompile, program_utils::limited_deserialize, pubkey::Pubkey, sanitize::Sanitize, - secp256k1_instruction::verify_eth_addresses, - secp256k1_program, signature::Signature, solana_sdk::feature_set, transaction::{Result, Transaction, TransactionError, VersionedTransaction}, @@ -205,37 +203,16 @@ impl SanitizedTransaction { } } - /// Verify the encoded secp256k1 signatures in this transaction + /// Verify the precompiled programs in this transaction pub fn verify_precompiles(&self, feature_set: &Arc) -> Result<()> { for (program_id, instruction) in self.message.program_instructions_iter() { - if secp256k1_program::check_id(program_id) { - let instruction_datas: Vec<_> = self - .message - .instructions() - .iter() - .map(|instruction| instruction.data.as_ref()) - .collect(); - let data = &instruction.data; - let e = verify_eth_addresses( - data, - &instruction_datas, - feature_set.is_active(&feature_set::libsecp256k1_0_5_upgrade_enabled::id()), - feature_set.is_active(&feature_set::libsecp256k1_fail_on_bad_count::id()), - ); - e.map_err(|_| TransactionError::InvalidAccountIndex)?; - } else if crate::ed25519_program::check_id(program_id) - && feature_set.is_active(&feature_set::ed25519_program_enabled::id()) - { - let instruction_datas: Vec<_> = self - .message() - .instructions() - .iter() - .map(|instruction| instruction.data.as_ref()) - .collect(); - let data = &instruction.data; - let e = verify_signatures(data, &instruction_datas); - e.map_err(|_| TransactionError::InvalidAccountIndex)?; - } + verify_if_precompile( + program_id, + instruction, + self.message().instructions(), + feature_set, + ) + .map_err(|_| TransactionError::InvalidAccountIndex)?; } Ok(()) }