Cleanup and standardize precompiles (#19918)
This commit is contained in:
@ -1090,7 +1090,7 @@ fn test_program_bpf_invoke_sanity() {
|
|||||||
result.unwrap_err(),
|
result.unwrap_err(),
|
||||||
TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
|
TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bpf_rust")]
|
#[cfg(feature = "bpf_rust")]
|
||||||
|
@ -1,27 +1,9 @@
|
|||||||
#![cfg(feature = "full")]
|
#![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 bytemuck::{bytes_of, Pod, Zeroable};
|
||||||
use ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier};
|
use ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier};
|
||||||
use thiserror::Error;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const PUBKEY_SERIALIZED_SIZE: usize = 32;
|
pub const PUBKEY_SERIALIZED_SIZE: usize = 32;
|
||||||
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
|
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 {
|
if data.len() < SIGNATURE_OFFSETS_START {
|
||||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
let num_signatures = data[0] as usize;
|
let num_signatures = data[0] as usize;
|
||||||
if num_signatures == 0 && data.len() > SIGNATURE_OFFSETS_START {
|
if num_signatures == 0 && data.len() > SIGNATURE_OFFSETS_START {
|
||||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
let expected_data_size = num_signatures
|
let expected_data_size = num_signatures
|
||||||
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
||||||
.saturating_add(SIGNATURE_OFFSETS_START);
|
.saturating_add(SIGNATURE_OFFSETS_START);
|
||||||
if data.len() < expected_data_size {
|
if data.len() < expected_data_size {
|
||||||
return Err(Ed25519Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
for i in 0..num_signatures {
|
for i in 0..num_signatures {
|
||||||
let start = i
|
let start = i
|
||||||
@ -117,23 +103,23 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(),
|
|||||||
|
|
||||||
// bytemuck wants structures aligned
|
// bytemuck wants structures aligned
|
||||||
let offsets: &Ed25519SignatureOffsets = bytemuck::try_from_bytes(&data[start..end])
|
let offsets: &Ed25519SignatureOffsets = bytemuck::try_from_bytes(&data[start..end])
|
||||||
.map_err(|_| Ed25519Error::InvalidDataOffsets)?;
|
.map_err(|_| PrecompileError::InvalidDataOffsets)?;
|
||||||
|
|
||||||
// Parse out signature
|
// Parse out signature
|
||||||
let signature_index = offsets.signature_instruction_index as usize;
|
let signature_index = offsets.signature_instruction_index as usize;
|
||||||
if signature_index >= instruction_datas.len() {
|
if signature_index >= instruction_datas.len() {
|
||||||
return Err(Ed25519Error::InvalidDataOffsets);
|
return Err(PrecompileError::InvalidDataOffsets);
|
||||||
}
|
}
|
||||||
let signature_instruction = instruction_datas[signature_index];
|
let signature_instruction = instruction_datas[signature_index];
|
||||||
let sig_start = offsets.signature_offset as usize;
|
let sig_start = offsets.signature_offset as usize;
|
||||||
let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE);
|
let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE);
|
||||||
if sig_end >= signature_instruction.len() {
|
if sig_end >= signature_instruction.len() {
|
||||||
return Err(Ed25519Error::InvalidDataOffsets);
|
return Err(PrecompileError::InvalidDataOffsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
let signature =
|
let signature =
|
||||||
ed25519_dalek::Signature::from_bytes(&signature_instruction[sig_start..sig_end])
|
ed25519_dalek::Signature::from_bytes(&signature_instruction[sig_start..sig_end])
|
||||||
.map_err(|_| Ed25519Error::InvalidSignature)?;
|
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||||
|
|
||||||
// Parse out pubkey
|
// Parse out pubkey
|
||||||
let pubkey = get_data_slice(
|
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)
|
let publickey = ed25519_dalek::PublicKey::from_bytes(pubkey)
|
||||||
.map_err(|_| Ed25519Error::InvalidPublicKey)?;
|
.map_err(|_| PrecompileError::InvalidPublicKey)?;
|
||||||
|
|
||||||
// Parse out message
|
// Parse out message
|
||||||
let message = get_data_slice(
|
let message = get_data_slice(
|
||||||
@ -156,7 +142,7 @@ pub fn verify_signatures(data: &[u8], instruction_datas: &[&[u8]]) -> Result<(),
|
|||||||
|
|
||||||
publickey
|
publickey
|
||||||
.verify(message, &signature)
|
.verify(message, &signature)
|
||||||
.map_err(|_| Ed25519Error::InvalidSignature)?;
|
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -166,16 +152,16 @@ fn get_data_slice<'a>(
|
|||||||
instruction_index: u16,
|
instruction_index: u16,
|
||||||
offset_start: u16,
|
offset_start: u16,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> Result<&'a [u8], Ed25519Error> {
|
) -> Result<&'a [u8], PrecompileError> {
|
||||||
let signature_index = instruction_index as usize;
|
let signature_index = instruction_index as usize;
|
||||||
if signature_index >= instruction_datas.len() {
|
if signature_index >= instruction_datas.len() {
|
||||||
return Err(Ed25519Error::InvalidDataOffsets);
|
return Err(PrecompileError::InvalidDataOffsets);
|
||||||
}
|
}
|
||||||
let signature_instruction = &instruction_datas[signature_index];
|
let signature_instruction = &instruction_datas[signature_index];
|
||||||
let start = offset_start as usize;
|
let start = offset_start as usize;
|
||||||
let end = start.saturating_add(size);
|
let end = start.saturating_add(size);
|
||||||
if end > signature_instruction.len() {
|
if end > signature_instruction.len() {
|
||||||
return Err(Ed25519Error::InvalidDataOffsets);
|
return Err(PrecompileError::InvalidDataOffsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(&instruction_datas[signature_index][start..end])
|
Ok(&instruction_datas[signature_index][start..end])
|
||||||
@ -188,7 +174,7 @@ pub mod test {
|
|||||||
fn test_case(
|
fn test_case(
|
||||||
num_signatures: u16,
|
num_signatures: u16,
|
||||||
offsets: &Ed25519SignatureOffsets,
|
offsets: &Ed25519SignatureOffsets,
|
||||||
) -> Result<(), Ed25519Error> {
|
) -> Result<(), PrecompileError> {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytemuck::bytes_of(offsets).len(),
|
bytemuck::bytes_of(offsets).len(),
|
||||||
SIGNATURE_OFFSETS_SERIALIZED_SIZE
|
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[0..SIGNATURE_OFFSETS_START].copy_from_slice(bytes_of(&num_signatures));
|
||||||
instruction_data[SIGNATURE_OFFSETS_START..DATA_START].copy_from_slice(bytes_of(offsets));
|
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]
|
#[test]
|
||||||
@ -212,8 +202,12 @@ pub mod test {
|
|||||||
instruction_data.truncate(instruction_data.len() - 1);
|
instruction_data.truncate(instruction_data.len() - 1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_signatures(&instruction_data, &[&[0u8; 100]]),
|
verify(
|
||||||
Err(Ed25519Error::InvalidInstructionDataSize)
|
&instruction_data,
|
||||||
|
&[&[0u8; 100]],
|
||||||
|
&Arc::new(FeatureSet::all_enabled()),
|
||||||
|
),
|
||||||
|
Err(PrecompileError::InvalidInstructionDataSize)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -222,7 +216,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -231,7 +225,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -240,7 +234,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +245,10 @@ pub mod test {
|
|||||||
message_data_size: 1,
|
message_data_size: 1,
|
||||||
..Ed25519SignatureOffsets::default()
|
..Ed25519SignatureOffsets::default()
|
||||||
};
|
};
|
||||||
assert_eq!(test_case(1, &offsets), Err(Ed25519Error::InvalidSignature));
|
assert_eq!(
|
||||||
|
test_case(1, &offsets),
|
||||||
|
Err(PrecompileError::InvalidSignature)
|
||||||
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
message_data_offset: 100,
|
message_data_offset: 100,
|
||||||
@ -260,7 +257,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -270,7 +267,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -280,7 +277,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +289,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -301,7 +298,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +310,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Ed25519Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = Ed25519SignatureOffsets {
|
let offsets = Ed25519SignatureOffsets {
|
||||||
@ -322,7 +319,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
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 nonce_keyed_account;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod poh_config;
|
pub mod poh_config;
|
||||||
|
pub mod precompiles;
|
||||||
pub mod process_instruction;
|
pub mod process_instruction;
|
||||||
pub mod program_utils;
|
pub mod program_utils;
|
||||||
pub mod pubkey;
|
pub mod pubkey;
|
||||||
|
117
sdk/src/precompiles.rs
Normal file
117
sdk/src/precompiles.rs
Normal file
@ -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")]
|
#![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 digest::Digest;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Secp256k1Error {
|
|
||||||
InvalidSignature,
|
|
||||||
InvalidRecoveryId,
|
|
||||||
InvalidDataOffsets,
|
|
||||||
InvalidInstructionDataSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20;
|
pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20;
|
||||||
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
|
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
|
||||||
@ -99,27 +96,27 @@ pub fn construct_eth_pubkey(
|
|||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_eth_addresses(
|
pub fn verify(
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
instruction_datas: &[&[u8]],
|
instruction_datas: &[&[u8]],
|
||||||
libsecp256k1_0_5_upgrade_enabled: bool,
|
feature_set: &Arc<FeatureSet>,
|
||||||
libsecp256k1_fail_on_bad_count: bool,
|
) -> Result<(), PrecompileError> {
|
||||||
) -> Result<(), Secp256k1Error> {
|
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
let count = data[0] as usize;
|
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
|
// count is zero but the instruction data indicates that is probably not
|
||||||
// correct, fail the instruction to catch probable invalid secp256k1
|
// correct, fail the instruction to catch probable invalid secp256k1
|
||||||
// instruction construction.
|
// instruction construction.
|
||||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
let expected_data_size = count
|
let expected_data_size = count
|
||||||
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
.saturating_mul(SIGNATURE_OFFSETS_SERIALIZED_SIZE)
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
if data.len() < expected_data_size {
|
if data.len() < expected_data_size {
|
||||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let start = i
|
let start = i
|
||||||
@ -128,21 +125,21 @@ pub fn verify_eth_addresses(
|
|||||||
let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE);
|
let end = start.saturating_add(SIGNATURE_OFFSETS_SERIALIZED_SIZE);
|
||||||
|
|
||||||
let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end])
|
let offsets: SecpSignatureOffsets = bincode::deserialize(&data[start..end])
|
||||||
.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||||
|
|
||||||
// Parse out signature
|
// Parse out signature
|
||||||
let signature_index = offsets.signature_instruction_index as usize;
|
let signature_index = offsets.signature_instruction_index as usize;
|
||||||
if signature_index >= instruction_datas.len() {
|
if signature_index >= instruction_datas.len() {
|
||||||
return Err(Secp256k1Error::InvalidInstructionDataSize);
|
return Err(PrecompileError::InvalidInstructionDataSize);
|
||||||
}
|
}
|
||||||
let signature_instruction = instruction_datas[signature_index];
|
let signature_instruction = instruction_datas[signature_index];
|
||||||
let sig_start = offsets.signature_offset as usize;
|
let sig_start = offsets.signature_offset as usize;
|
||||||
let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE);
|
let sig_end = sig_start.saturating_add(SIGNATURE_SERIALIZED_SIZE);
|
||||||
if sig_end >= signature_instruction.len() {
|
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(
|
libsecp256k1::Signature::parse_standard_slice(
|
||||||
&signature_instruction[sig_start..sig_end],
|
&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])
|
let recovery_id = libsecp256k1::RecoveryId::parse(signature_instruction[sig_end])
|
||||||
.map_err(|_| Secp256k1Error::InvalidRecoveryId)?;
|
.map_err(|_| PrecompileError::InvalidRecoveryId)?;
|
||||||
|
|
||||||
// Parse out pubkey
|
// Parse out pubkey
|
||||||
let eth_address_slice = get_data_slice(
|
let eth_address_slice = get_data_slice(
|
||||||
@ -182,11 +179,11 @@ pub fn verify_eth_addresses(
|
|||||||
&signature,
|
&signature,
|
||||||
&recovery_id,
|
&recovery_id,
|
||||||
)
|
)
|
||||||
.map_err(|_| Secp256k1Error::InvalidSignature)?;
|
.map_err(|_| PrecompileError::InvalidSignature)?;
|
||||||
let eth_address = construct_eth_pubkey(&pubkey);
|
let eth_address = construct_eth_pubkey(&pubkey);
|
||||||
|
|
||||||
if eth_address_slice != eth_address {
|
if eth_address_slice != eth_address {
|
||||||
return Err(Secp256k1Error::InvalidSignature);
|
return Err(PrecompileError::InvalidSignature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -197,16 +194,16 @@ fn get_data_slice<'a>(
|
|||||||
instruction_index: u8,
|
instruction_index: u8,
|
||||||
offset_start: u16,
|
offset_start: u16,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> Result<&'a [u8], Secp256k1Error> {
|
) -> Result<&'a [u8], PrecompileError> {
|
||||||
let signature_index = instruction_index as usize;
|
let signature_index = instruction_index as usize;
|
||||||
if signature_index >= instruction_datas.len() {
|
if signature_index >= instruction_datas.len() {
|
||||||
return Err(Secp256k1Error::InvalidDataOffsets);
|
return Err(PrecompileError::InvalidDataOffsets);
|
||||||
}
|
}
|
||||||
let signature_instruction = &instruction_datas[signature_index];
|
let signature_instruction = &instruction_datas[signature_index];
|
||||||
let start = offset_start as usize;
|
let start = offset_start as usize;
|
||||||
let end = start.saturating_add(size);
|
let end = start.saturating_add(size);
|
||||||
if end > signature_instruction.len() {
|
if end > signature_instruction.len() {
|
||||||
return Err(Secp256k1Error::InvalidSignature);
|
return Err(PrecompileError::InvalidSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(&instruction_datas[signature_index][start..end])
|
Ok(&instruction_datas[signature_index][start..end])
|
||||||
@ -216,13 +213,23 @@ fn get_data_slice<'a>(
|
|||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
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];
|
let mut instruction_data = vec![0u8; DATA_START];
|
||||||
instruction_data[0] = num_signatures;
|
instruction_data[0] = num_signatures;
|
||||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||||
bincode::serialize_into(writer, &offsets).unwrap();
|
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]
|
#[test]
|
||||||
@ -235,10 +242,17 @@ pub mod test {
|
|||||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||||
bincode::serialize_into(writer, &offsets).unwrap();
|
bincode::serialize_into(writer, &offsets).unwrap();
|
||||||
instruction_data.truncate(instruction_data.len() - 1);
|
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!(
|
assert_eq!(
|
||||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
|
verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)),
|
||||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
Err(PrecompileError::InvalidInstructionDataSize)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -247,7 +261,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
Err(PrecompileError::InvalidInstructionDataSize)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -256,7 +270,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -265,7 +279,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidDataOffsets)
|
Err(PrecompileError::InvalidDataOffsets)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +292,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -288,7 +302,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -298,7 +312,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -308,7 +322,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +334,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -329,7 +343,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +355,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
|
|
||||||
let offsets = SecpSignatureOffsets {
|
let offsets = SecpSignatureOffsets {
|
||||||
@ -350,7 +364,7 @@ pub mod test {
|
|||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test_case(1, &offsets),
|
test_case(1, &offsets),
|
||||||
Err(Secp256k1Error::InvalidSignature)
|
Err(PrecompileError::InvalidSignature)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,9 +377,17 @@ pub mod test {
|
|||||||
instruction_data[0] = 0;
|
instruction_data[0] = 0;
|
||||||
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
let writer = std::io::Cursor::new(&mut instruction_data[1..]);
|
||||||
bincode::serialize_into(writer, &offsets).unwrap();
|
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!(
|
assert_eq!(
|
||||||
verify_eth_addresses(&instruction_data, &[&[0u8; 100]], false, true),
|
verify(&instruction_data, &[&[0u8; 100]], &Arc::new(feature_set)),
|
||||||
Err(Secp256k1Error::InvalidInstructionDataSize)
|
Err(PrecompileError::InvalidInstructionDataSize)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,14 @@
|
|||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
ed25519_instruction::verify_signatures,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||||
message::{Message, SanitizeMessageError},
|
message::{Message, SanitizeMessageError},
|
||||||
nonce::NONCED_TX_MARKER_IX_INDEX,
|
nonce::NONCED_TX_MARKER_IX_INDEX,
|
||||||
|
precompiles::verify_if_precompile,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::{Sanitize, SanitizeError},
|
sanitize::{Sanitize, SanitizeError},
|
||||||
secp256k1_instruction::verify_eth_addresses,
|
|
||||||
short_vec,
|
short_vec,
|
||||||
signature::{Signature, SignerError},
|
signature::{Signature, SignerError},
|
||||||
signers::Signers,
|
signers::Signers,
|
||||||
@ -433,6 +432,7 @@ impl Transaction {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify the precompiled programs in this transaction
|
||||||
pub fn verify_precompiles(&self, feature_set: &Arc<feature_set::FeatureSet>) -> Result<()> {
|
pub fn verify_precompiles(&self, feature_set: &Arc<feature_set::FeatureSet>) -> Result<()> {
|
||||||
for instruction in &self.message().instructions {
|
for instruction in &self.message().instructions {
|
||||||
// The Transaction may not be sanitized at this point
|
// The Transaction may not be sanitized at this point
|
||||||
@ -440,34 +440,14 @@ impl Transaction {
|
|||||||
return Err(TransactionError::AccountNotFound);
|
return Err(TransactionError::AccountNotFound);
|
||||||
}
|
}
|
||||||
let program_id = &self.message().account_keys[instruction.program_id_index as usize];
|
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
|
verify_if_precompile(
|
||||||
.message()
|
program_id,
|
||||||
.instructions
|
instruction,
|
||||||
.iter()
|
&self.message().instructions,
|
||||||
.map(|instruction| instruction.data.as_ref())
|
feature_set,
|
||||||
.collect();
|
)
|
||||||
let data = &instruction.data;
|
.map_err(|_| TransactionError::InvalidAccountIndex)?;
|
||||||
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)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
ed25519_instruction::verify_signatures,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
message::{v0, MappedAddresses, MappedMessage, SanitizedMessage, VersionedMessage},
|
message::{v0, MappedAddresses, MappedMessage, SanitizedMessage, VersionedMessage},
|
||||||
nonce::NONCED_TX_MARKER_IX_INDEX,
|
nonce::NONCED_TX_MARKER_IX_INDEX,
|
||||||
|
precompiles::verify_if_precompile,
|
||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::Sanitize,
|
sanitize::Sanitize,
|
||||||
secp256k1_instruction::verify_eth_addresses,
|
|
||||||
secp256k1_program,
|
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
solana_sdk::feature_set,
|
solana_sdk::feature_set,
|
||||||
transaction::{Result, Transaction, TransactionError, VersionedTransaction},
|
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<()> {
|
pub fn verify_precompiles(&self, feature_set: &Arc<feature_set::FeatureSet>) -> Result<()> {
|
||||||
for (program_id, instruction) in self.message.program_instructions_iter() {
|
for (program_id, instruction) in self.message.program_instructions_iter() {
|
||||||
if secp256k1_program::check_id(program_id) {
|
verify_if_precompile(
|
||||||
let instruction_datas: Vec<_> = self
|
program_id,
|
||||||
.message
|
instruction,
|
||||||
.instructions()
|
self.message().instructions(),
|
||||||
.iter()
|
feature_set,
|
||||||
.map(|instruction| instruction.data.as_ref())
|
)
|
||||||
.collect();
|
.map_err(|_| TransactionError::InvalidAccountIndex)?;
|
||||||
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)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user