Proposal: log binary data for Solidity

The program_id is not needed on "Program return data: " because it
always preceeded by the program invoke message, so no need to repeat
the program id. Also rename this to "Program return: " since "data"
is redundant.
This commit is contained in:
Sean Young
2021-09-17 09:14:49 +01:00
parent 1fa8b6b966
commit d714cf659c
17 changed files with 432 additions and 10 deletions

View File

@ -939,7 +939,7 @@ impl Executor for BpfExecutor {
drop(vm);
let return_data = invoke_context.get_return_data();
if let Some((program_id, return_data)) = return_data {
stable_log::program_return_data(&logger, program_id, return_data);
stable_log::program_return(&logger, program_id, return_data);
}
match result {
Ok(status) => {

View File

@ -22,7 +22,7 @@ use solana_sdk::{
allow_native_ids, blake3_syscall_enabled, check_seed_length,
close_upgradeable_program_accounts, demote_program_write_locks, disable_fees_sysvar,
libsecp256k1_0_5_upgrade_enabled, mem_overlap_fix, return_data_syscall_enabled,
secp256k1_recover_syscall_enabled,
secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled,
},
hash::{Hasher, HASH_BYTES},
ic_msg,
@ -183,6 +183,11 @@ pub fn register_syscalls(
.register_syscall_by_name(b"sol_get_return_data", SyscallGetReturnData::call)?;
}
// Log data
if invoke_context.is_feature_active(&sol_log_data_syscall_enabled::id()) {
syscall_registry.register_syscall_by_name(b"sol_log_data", SyscallLogData::call)?;
}
Ok(syscall_registry)
}
@ -357,6 +362,8 @@ pub fn bind_syscall_context_objects<'a>(
!invoke_context.is_feature_active(&disable_fees_sysvar::id());
let is_return_data_syscall_active =
invoke_context.is_feature_active(&return_data_syscall_enabled::id());
let is_sol_log_data_syscall_active =
invoke_context.is_feature_active(&sol_log_data_syscall_enabled::id());
let invoke_context = Rc::new(RefCell::new(invoke_context));
@ -409,6 +416,16 @@ pub fn bind_syscall_context_objects<'a>(
}),
);
// sol_log_data
bind_feature_gated_syscall_context_object!(
vm,
is_sol_log_data_syscall_active,
Box::new(SyscallLogData {
invoke_context: invoke_context.clone(),
loader_id,
}),
);
// Cross-program invocation syscalls
vm.bind_syscall_context_object(
Box::new(SyscallInvokeSignedC {
@ -2381,6 +2398,72 @@ impl<'a> SyscallObject<BpfError> for SyscallGetReturnData<'a> {
}
}
// Log data handling
pub struct SyscallLogData<'a> {
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
loader_id: &'a Pubkey,
}
impl<'a> SyscallObject<BpfError> for SyscallLogData<'a> {
fn call(
&mut self,
addr: u64,
len: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>,
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let budget = invoke_context.get_compute_budget();
question_mark!(
invoke_context
.get_compute_meter()
.consume(budget.syscall_base_cost),
result
);
let untranslated_fields = question_mark!(
translate_slice::<&[u8]>(memory_mapping, addr, len, self.loader_id),
result
);
question_mark!(
invoke_context
.get_compute_meter()
.consume(untranslated_fields.iter().map(|e| e.len() as u64).sum()),
result
);
let mut fields = Vec::with_capacity(untranslated_fields.len());
for untranslated_field in untranslated_fields {
fields.push(question_mark!(
translate_slice::<u8>(
memory_mapping,
untranslated_field.as_ptr() as *const _ as u64,
untranslated_field.len() as u64,
self.loader_id,
),
result
));
}
let logger = invoke_context.get_logger();
stable_log::program_data(&logger, &fields);
*result = Ok(0);
}
}
#[cfg(test)]
mod tests {
use super::*;