-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add gas limit #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
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
This file contains hidden or 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 hidden or 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 |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use polkavm::Linker; | ||
|
||
pub trait PvqExecutorContext { | ||
type UserData; | ||
type UserError; | ||
fn register_host_functions(&mut self, linker: &mut Linker<Self::UserData, Self::UserError>); | ||
fn data(&mut self) -> &mut Self::UserData; | ||
} |
This file contains hidden or 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 |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use pvq_primitives::PvqError; | ||
#[derive(Debug)] | ||
pub enum PvqExecutorError<UserError> { | ||
InvalidProgramFormat, | ||
MemoryAccessError(polkavm::MemoryAccessError), | ||
// Extract from the PVM CallError | ||
Trap, | ||
// Extract from the PVM CallError | ||
NotEnoughGas, | ||
// Usually a custom error type from the extension system definition | ||
User(UserError), | ||
// Other errors directly from the PVM | ||
OtherPvmError(polkavm::Error), | ||
} | ||
|
||
impl<UserError> From<polkavm::MemoryAccessError> for PvqExecutorError<UserError> { | ||
fn from(err: polkavm::MemoryAccessError) -> Self { | ||
Self::MemoryAccessError(err) | ||
} | ||
} | ||
|
||
impl<UserError> From<polkavm::Error> for PvqExecutorError<UserError> { | ||
fn from(err: polkavm::Error) -> Self { | ||
Self::OtherPvmError(err) | ||
} | ||
} | ||
|
||
impl<UserError> From<polkavm::CallError<UserError>> for PvqExecutorError<UserError> { | ||
fn from(err: polkavm::CallError<UserError>) -> Self { | ||
match err { | ||
polkavm::CallError::Trap => Self::Trap, | ||
polkavm::CallError::NotEnoughGas => Self::NotEnoughGas, | ||
polkavm::CallError::Error(e) => Self::OtherPvmError(e), | ||
polkavm::CallError::User(e) => Self::User(e), | ||
} | ||
} | ||
} | ||
|
||
impl<UserError> From<PvqExecutorError<UserError>> for PvqError { | ||
fn from(e: PvqExecutorError<UserError>) -> PvqError { | ||
match e { | ||
PvqExecutorError::InvalidProgramFormat => PvqError::InvalidPvqProgramFormat, | ||
PvqExecutorError::MemoryAccessError(_) => PvqError::MemoryAccessError, | ||
PvqExecutorError::Trap => PvqError::Trap, | ||
PvqExecutorError::NotEnoughGas => PvqError::QueryExceedsWeightLimit, | ||
PvqExecutorError::User(_) => PvqError::HostCallError, | ||
PvqExecutorError::OtherPvmError(_) => PvqError::Other, | ||
} | ||
} | ||
} |
This file contains hidden or 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 |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use alloc::vec::Vec; | ||
use polkavm::{Config, Engine, Linker, Module, ModuleConfig, ProgramBlob}; | ||
|
||
use crate::context::PvqExecutorContext; | ||
use crate::error::PvqExecutorError; | ||
|
||
type PvqExecutorResult<UserError> = Result<Vec<u8>, PvqExecutorError<UserError>>; | ||
type GasLimit = Option<i64>; | ||
|
||
pub struct PvqExecutor<Ctx: PvqExecutorContext> { | ||
engine: Engine, | ||
linker: Linker<Ctx::UserData, Ctx::UserError>, | ||
context: Ctx, | ||
} | ||
|
||
impl<Ctx: PvqExecutorContext> PvqExecutor<Ctx> { | ||
pub fn new(config: Config, mut context: Ctx) -> Self { | ||
let engine = Engine::new(&config).unwrap(); | ||
let mut linker = Linker::<Ctx::UserData, Ctx::UserError>::new(); | ||
// Register user-defined host functions | ||
context.register_host_functions(&mut linker); | ||
Self { | ||
engine, | ||
linker, | ||
context, | ||
} | ||
} | ||
|
||
pub fn execute( | ||
&mut self, | ||
program: &[u8], | ||
args: &[u8], | ||
gas_limit: GasLimit, | ||
) -> (PvqExecutorResult<Ctx::UserError>, GasLimit) { | ||
let blob = match ProgramBlob::parse(program.into()) { | ||
Ok(blob) => blob, | ||
Err(_) => return (Err(PvqExecutorError::InvalidProgramFormat), gas_limit), | ||
}; | ||
|
||
// TODO: make this configurable | ||
let mut module_config = ModuleConfig::new(); | ||
module_config.set_aux_data_size(args.len() as u32); | ||
if gas_limit.is_some() { | ||
module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync)); | ||
} | ||
|
||
let module = match Module::from_blob(&self.engine, &module_config, blob) { | ||
Ok(module) => module, | ||
Err(err) => return (Err(err.into()), gas_limit), | ||
}; | ||
|
||
let instance_pre = match self.linker.instantiate_pre(&module) { | ||
Ok(instance_pre) => instance_pre, | ||
Err(err) => return (Err(err.into()), gas_limit), | ||
}; | ||
|
||
let mut instance = match instance_pre.instantiate() { | ||
Ok(instance) => instance, | ||
Err(err) => return (Err(err.into()), gas_limit), | ||
}; | ||
|
||
if let Some(gas_limit) = gas_limit { | ||
instance.set_gas(gas_limit); | ||
} | ||
|
||
// From this point on, we include instance.gas() in the return value | ||
let result = (|| { | ||
instance.write_memory(module.memory_map().aux_data_address(), args)?; | ||
|
||
tracing::info!("Calling entrypoint with args: {:?}", args); | ||
let res = instance.call_typed_and_get_result::<u64, (u32, u32)>( | ||
self.context.data(), | ||
"pvq", | ||
(module.memory_map().aux_data_address(), args.len() as u32), | ||
)?; | ||
|
||
let res_size = (res >> 32) as u32; | ||
let res_ptr = (res & 0xffffffff) as u32; | ||
|
||
let result = instance.read_memory(res_ptr, res_size)?; | ||
|
||
tracing::info!("Result: {:?}", result); | ||
Ok(result) | ||
})(); | ||
|
||
if gas_limit.is_some() { | ||
(result, Some(instance.gas())) | ||
} else { | ||
(result, None) | ||
} | ||
} | ||
} |
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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.
Uh oh!
There was an error while loading. Please reload this page.
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.
should take an optional gas limit as input to and max to like 2s of execution to prevent for people calling infinite loop
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.
Is the max execution time related to gas_limit or they are separately specified like
execute_query(query: &[u8], input: &[u8], gas_limit: Option<i64>, ref_time_limit: u64)
? I supposed they should be related.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.
the input is gas limit. by 2s I mean estimate how much gas can be consumed to execute a code that takes 2s to complete