Cleanup and standardize precompiles (#19918)
This commit is contained in:
parent
99f5684dc4
commit
fc2bf2d3b6
|
@ -1090,7 +1090,7 @@ fn test_program_bpf_invoke_sanity() {
|
|||
result.unwrap_err(),
|
||||
TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
|
|
|
@ -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<T> DecodeError<T> 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<FeatureSet>,
|
||||
) -> 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<T> DecodeError<T> for PrecompileError {
|
||||
fn type_of() -> &'static str {
|
||||
"PrecompileError"
|
||||
}
|
||||
}
|
||||
|
||||
/// All precompiled programs must implement the `Verify` function
|
||||
pub type Verify = fn(&[u8], &[&[u8]], &Arc<FeatureSet>) -> 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<Pubkey>,
|
||||
/// Verification function
|
||||
pub verify_fn: Verify,
|
||||
}
|
||||
impl Precompile {
|
||||
/// Creates a new `Precompile`
|
||||
pub fn new(program_id: Pubkey, feature: Option<Pubkey>, 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<FeatureSet>) -> 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<FeatureSet>,
|
||||
) -> std::result::Result<(), PrecompileError> {
|
||||
(self.verify_fn)(data, instruction_datas, feature_set)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// The list of all precompiled programs
|
||||
static ref PRECOMPILES: Vec<Precompile> = 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<FeatureSet>) -> 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<FeatureSet>,
|
||||
) -> 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(())
|
||||
}
|
|
@ -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<FeatureSet>,
|
||||
) -> 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<feature_set::FeatureSet>) -> 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(())
|
||||
}
|
||||
|
|
|
@ -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<feature_set::FeatureSet>) -> 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(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue