This repository has been archived by the owner on Jan 13, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Refactor - Cleanup error handling in program runtime #30693
Merged
Lichtso
merged 8 commits into
solana-labs:master
from
Lichtso:refactor/cleanup_error_handling
Apr 5, 2023
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9674b78
Moves stable_log::program_invoke(), stable_log::program_success() and…
Lichtso b3cae93
Turns result of ProcessInstructionWithContext from InstructionError i…
Lichtso 6d22d4a
Bump to solana_rbpf v0.3.0
Lichtso 167ff2d
Removes Result from return type of EbpfVm::new().
Lichtso b3f7ee5
Turns EbpfError into Box<dyn std::error::Error>.
Lichtso 56aa5d7
Removes BpfError.
Lichtso d079811
Removes SyscallError::InstructionError.
Lichtso 778c71d
Adds a type alias for Box<dyn std::error::Error> in syscalls.
Lichtso File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,7 +38,27 @@ use { | |
}, | ||
}; | ||
|
||
pub type ProcessInstructionWithContext = fn(&mut InvokeContext) -> Result<(), InstructionError>; | ||
/// Adapter so we can unify the interfaces of built-in programs and syscalls | ||
#[macro_export] | ||
macro_rules! declare_process_instruction { | ||
($cu_to_consume:expr) => { | ||
pub fn process_instruction( | ||
invoke_context: &mut InvokeContext, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
if invoke_context | ||
.feature_set | ||
.is_active(&feature_set::native_programs_consume_cu::id()) | ||
{ | ||
invoke_context.consume_checked($cu_to_consume)?; | ||
} | ||
process_instruction_inner(invoke_context) | ||
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>) | ||
} | ||
}; | ||
} | ||
|
||
pub type ProcessInstructionWithContext = | ||
fn(&mut InvokeContext) -> Result<(), Box<dyn std::error::Error>>; | ||
|
||
#[derive(Clone)] | ||
pub struct BuiltinProgram { | ||
|
@@ -50,7 +70,7 @@ impl std::fmt::Debug for BuiltinProgram { | |
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
// These are just type aliases for work around of Debug-ing above pointers | ||
type ErasedProcessInstructionWithContext = | ||
fn(&'static mut InvokeContext<'static>) -> Result<(), InstructionError>; | ||
fn(&'static mut InvokeContext<'static>) -> Result<(), Box<dyn std::error::Error>>; | ||
|
||
// rustc doesn't compile due to bug without this work around | ||
// https://github.com/rust-lang/rust/issues/50280 | ||
|
@@ -689,26 +709,25 @@ impl<'a> InvokeContext<'a> { | |
self.transaction_context | ||
.set_return_data(program_id, Vec::new())?; | ||
|
||
let is_builtin_program = builtin_id == program_id; | ||
let pre_remaining_units = self.get_remaining(); | ||
let result = if is_builtin_program { | ||
let logger = self.get_log_collector(); | ||
stable_log::program_invoke(&logger, &program_id, self.get_stack_height()); | ||
(entry.process_instruction)(self) | ||
.map(|()| { | ||
stable_log::program_success(&logger, &program_id); | ||
}) | ||
.map_err(|err| { | ||
stable_log::program_failure(&logger, &program_id, &err); | ||
err | ||
}) | ||
} else { | ||
(entry.process_instruction)(self) | ||
}; | ||
let logger = self.get_log_collector(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always wondered what this extra if was for |
||
stable_log::program_invoke(&logger, &program_id, self.get_stack_height()); | ||
let result = (entry.process_instruction)(self) | ||
.map(|()| { | ||
stable_log::program_success(&logger, &program_id); | ||
}) | ||
.map_err(|err| { | ||
stable_log::program_failure(&logger, &program_id, err.as_ref()); | ||
if let Some(err) = err.downcast_ref::<InstructionError>() { | ||
err.clone() | ||
} else { | ||
InstructionError::ProgramFailedToComplete | ||
} | ||
}); | ||
let post_remaining_units = self.get_remaining(); | ||
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units); | ||
|
||
if is_builtin_program | ||
if builtin_id == program_id | ||
&& result.is_ok() | ||
&& *compute_units_consumed == 0 | ||
&& self | ||
|
@@ -739,13 +758,13 @@ impl<'a> InvokeContext<'a> { | |
} | ||
|
||
/// Consume compute units | ||
pub fn consume_checked(&self, amount: u64) -> Result<(), InstructionError> { | ||
pub fn consume_checked(&self, amount: u64) -> Result<(), Box<dyn std::error::Error>> { | ||
self.log_consumed_bpf_units(amount); | ||
let mut compute_meter = self.compute_meter.borrow_mut(); | ||
let exceeded = *compute_meter < amount; | ||
*compute_meter = compute_meter.saturating_sub(amount); | ||
if exceeded { | ||
return Err(InstructionError::ComputationalBudgetExceeded); | ||
return Err(Box::new(InstructionError::ComputationalBudgetExceeded)); | ||
} | ||
Ok(()) | ||
} | ||
|
@@ -986,14 +1005,14 @@ mod tests { | |
|
||
#[test] | ||
fn test_program_entry_debug() { | ||
#[allow(clippy::unnecessary_wraps)] | ||
fn mock_process_instruction( | ||
_invoke_context: &mut InvokeContext, | ||
) -> Result<(), InstructionError> { | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
Ok(()) | ||
} | ||
#[allow(clippy::unnecessary_wraps)] | ||
fn mock_ix_processor(_invoke_context: &mut InvokeContext) -> Result<(), InstructionError> { | ||
fn mock_ix_processor( | ||
_invoke_context: &mut InvokeContext, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
Ok(()) | ||
} | ||
let builtin_programs = &[ | ||
|
@@ -1014,7 +1033,7 @@ mod tests { | |
#[allow(clippy::integer_arithmetic)] | ||
fn mock_process_instruction( | ||
invoke_context: &mut InvokeContext, | ||
) -> Result<(), InstructionError> { | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
let transaction_context = &invoke_context.transaction_context; | ||
let instruction_context = transaction_context.get_current_instruction_context()?; | ||
let instruction_data = instruction_context.get_instruction_data(); | ||
|
@@ -1048,7 +1067,7 @@ mod tests { | |
if let Ok(instruction) = bincode::deserialize(instruction_data) { | ||
match instruction { | ||
MockInstruction::NoopSuccess => (), | ||
MockInstruction::NoopFail => return Err(InstructionError::GenericError), | ||
MockInstruction::NoopFail => return Err(Box::new(InstructionError::GenericError)), | ||
MockInstruction::ModifyOwned => instruction_context | ||
.try_borrow_instruction_account(transaction_context, 0)? | ||
.set_data_from_slice(&[1])?, | ||
|
@@ -1098,14 +1117,15 @@ mod tests { | |
desired_result, | ||
} => { | ||
invoke_context.consume_checked(compute_units_to_consume)?; | ||
return desired_result; | ||
return desired_result | ||
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>); | ||
} | ||
MockInstruction::Resize { new_len } => instruction_context | ||
.try_borrow_instruction_account(transaction_context, 0)? | ||
.set_data(vec![0; new_len as usize])?, | ||
} | ||
} else { | ||
return Err(InstructionError::InvalidInstructionData); | ||
return Err(Box::new(InstructionError::InvalidInstructionData)); | ||
} | ||
Ok(()) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment explaining what this is for. In the context of this PR is
clear, but if you only look at the call sites they look pretty weird so people
will wonder what's going on