Feature: `SyscallSetAccountProperties` (#27444)
* Adds TransactionContextAttribute. * Adds SyscallSetAccountProperties. * Adds AccountPropertyUpdate factory methods to BorrowedAccount. * Categorizes syscalls exclusive to ABIv0/v1 and ABIv2.
This commit is contained in:
parent
242c9cb442
commit
0367c1a60c
|
@ -82,6 +82,8 @@ pub struct ComputeBudget {
|
||||||
pub heap_cost: u64,
|
pub heap_cost: u64,
|
||||||
/// Memory operation syscall base cost
|
/// Memory operation syscall base cost
|
||||||
pub mem_op_base_cost: u64,
|
pub mem_op_base_cost: u64,
|
||||||
|
/// Number of compute units consumed per AccountPropertyUpdate
|
||||||
|
pub account_property_update_cost: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ComputeBudget {
|
impl Default for ComputeBudget {
|
||||||
|
@ -120,6 +122,7 @@ impl ComputeBudget {
|
||||||
heap_size: None,
|
heap_size: None,
|
||||||
heap_cost: 8,
|
heap_cost: 8,
|
||||||
mem_op_base_cost: 10,
|
mem_op_base_cost: 10,
|
||||||
|
account_property_update_cost: 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ use {
|
||||||
},
|
},
|
||||||
hash::{Hasher, HASH_BYTES},
|
hash::{Hasher, HASH_BYTES},
|
||||||
instruction::{
|
instruction::{
|
||||||
AccountMeta, Instruction, InstructionError, ProcessedSiblingInstruction,
|
AccountMeta, AccountPropertyUpdate, Instruction, InstructionError,
|
||||||
TRANSACTION_LEVEL_STACK_HEIGHT,
|
ProcessedSiblingInstruction, TRANSACTION_LEVEL_STACK_HEIGHT,
|
||||||
},
|
},
|
||||||
keccak, native_loader,
|
keccak, native_loader,
|
||||||
precompiles::is_precompile,
|
precompiles::is_precompile,
|
||||||
|
@ -53,7 +53,7 @@ use {
|
||||||
Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
|
Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
|
||||||
},
|
},
|
||||||
sysvar::{Sysvar, SysvarId},
|
sysvar::{Sysvar, SysvarId},
|
||||||
transaction_context::InstructionAccount,
|
transaction_context::{InstructionAccount, TransactionContextAttribute},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
|
@ -122,6 +122,8 @@ pub enum SyscallError {
|
||||||
num_account_infos: u64,
|
num_account_infos: u64,
|
||||||
max_account_infos: u64,
|
max_account_infos: u64,
|
||||||
},
|
},
|
||||||
|
#[error("InvalidAttribute")]
|
||||||
|
InvalidAttribute,
|
||||||
}
|
}
|
||||||
impl From<SyscallError> for EbpfError<BpfError> {
|
impl From<SyscallError> for EbpfError<BpfError> {
|
||||||
fn from(error: SyscallError) -> Self {
|
fn from(error: SyscallError) -> Self {
|
||||||
|
@ -165,6 +167,7 @@ pub fn register_syscalls(
|
||||||
let disable_fees_sysvar = invoke_context
|
let disable_fees_sysvar = invoke_context
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&disable_fees_sysvar::id());
|
.is_active(&disable_fees_sysvar::id());
|
||||||
|
let is_abi_v2 = false;
|
||||||
|
|
||||||
let mut syscall_registry = SyscallRegistry::default();
|
let mut syscall_registry = SyscallRegistry::default();
|
||||||
|
|
||||||
|
@ -302,38 +305,61 @@ pub fn register_syscalls(
|
||||||
SyscallMemset::call,
|
SyscallMemset::call,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Cross-program invocation
|
if is_abi_v2 {
|
||||||
syscall_registry.register_syscall_by_name(
|
// Set account attributes
|
||||||
b"sol_invoke_signed_c",
|
syscall_registry.register_syscall_by_name(
|
||||||
SyscallInvokeSignedC::init,
|
b"sol_set_account_attributes",
|
||||||
SyscallInvokeSignedC::call,
|
SyscallSetAccountProperties::init,
|
||||||
)?;
|
SyscallSetAccountProperties::call,
|
||||||
syscall_registry.register_syscall_by_name(
|
)?;
|
||||||
b"sol_invoke_signed_rust",
|
} else {
|
||||||
SyscallInvokeSignedRust::init,
|
// Processed sibling instructions
|
||||||
SyscallInvokeSignedRust::call,
|
syscall_registry.register_syscall_by_name(
|
||||||
)?;
|
b"sol_get_processed_sibling_instruction",
|
||||||
|
SyscallGetProcessedSiblingInstruction::init,
|
||||||
|
SyscallGetProcessedSiblingInstruction::call,
|
||||||
|
)?;
|
||||||
|
|
||||||
// Memory allocator
|
// Stack height
|
||||||
register_feature_gated_syscall!(
|
syscall_registry.register_syscall_by_name(
|
||||||
syscall_registry,
|
b"sol_get_stack_height",
|
||||||
!disable_deploy_of_alloc_free_syscall,
|
SyscallGetStackHeight::init,
|
||||||
b"sol_alloc_free_",
|
SyscallGetStackHeight::call,
|
||||||
SyscallAllocFree::init,
|
)?;
|
||||||
SyscallAllocFree::call,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Return data
|
// Return data
|
||||||
syscall_registry.register_syscall_by_name(
|
syscall_registry.register_syscall_by_name(
|
||||||
b"sol_set_return_data",
|
b"sol_set_return_data",
|
||||||
SyscallSetReturnData::init,
|
SyscallSetReturnData::init,
|
||||||
SyscallSetReturnData::call,
|
SyscallSetReturnData::call,
|
||||||
)?;
|
)?;
|
||||||
syscall_registry.register_syscall_by_name(
|
syscall_registry.register_syscall_by_name(
|
||||||
b"sol_get_return_data",
|
b"sol_get_return_data",
|
||||||
SyscallGetReturnData::init,
|
SyscallGetReturnData::init,
|
||||||
SyscallGetReturnData::call,
|
SyscallGetReturnData::call,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Cross-program invocation
|
||||||
|
syscall_registry.register_syscall_by_name(
|
||||||
|
b"sol_invoke_signed_c",
|
||||||
|
SyscallInvokeSignedC::init,
|
||||||
|
SyscallInvokeSignedC::call,
|
||||||
|
)?;
|
||||||
|
syscall_registry.register_syscall_by_name(
|
||||||
|
b"sol_invoke_signed_rust",
|
||||||
|
SyscallInvokeSignedRust::init,
|
||||||
|
SyscallInvokeSignedRust::call,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Memory allocator
|
||||||
|
register_feature_gated_syscall!(
|
||||||
|
syscall_registry,
|
||||||
|
!disable_deploy_of_alloc_free_syscall,
|
||||||
|
b"sol_alloc_free_",
|
||||||
|
SyscallAllocFree::init,
|
||||||
|
SyscallAllocFree::call,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Log data
|
// Log data
|
||||||
syscall_registry.register_syscall_by_name(
|
syscall_registry.register_syscall_by_name(
|
||||||
|
@ -342,20 +368,6 @@ pub fn register_syscalls(
|
||||||
SyscallLogData::call,
|
SyscallLogData::call,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Processed sibling instructions
|
|
||||||
syscall_registry.register_syscall_by_name(
|
|
||||||
b"sol_get_processed_sibling_instruction",
|
|
||||||
SyscallGetProcessedSiblingInstruction::init,
|
|
||||||
SyscallGetProcessedSiblingInstruction::call,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Stack height
|
|
||||||
syscall_registry.register_syscall_by_name(
|
|
||||||
b"sol_get_stack_height",
|
|
||||||
SyscallGetStackHeight::init,
|
|
||||||
SyscallGetStackHeight::call,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(syscall_registry)
|
Ok(syscall_registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1858,6 +1870,110 @@ declare_syscall!(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
declare_syscall!(
|
||||||
|
/// Update the properties of accounts
|
||||||
|
SyscallSetAccountProperties,
|
||||||
|
fn call(
|
||||||
|
&mut self,
|
||||||
|
updates_addr: u64,
|
||||||
|
updates_count: u64,
|
||||||
|
_arg3: u64,
|
||||||
|
_arg4: u64,
|
||||||
|
_arg5: u64,
|
||||||
|
memory_mapping: &mut 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.saturating_add(
|
||||||
|
budget
|
||||||
|
.account_property_update_cost
|
||||||
|
.saturating_mul(updates_count)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
let instruction_context = question_mark!(
|
||||||
|
transaction_context
|
||||||
|
.get_current_instruction_context()
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
let updates = question_mark!(
|
||||||
|
translate_slice_mut::<AccountPropertyUpdate>(
|
||||||
|
memory_mapping,
|
||||||
|
updates_addr,
|
||||||
|
updates_count,
|
||||||
|
invoke_context.get_check_aligned(),
|
||||||
|
invoke_context.get_check_size(),
|
||||||
|
),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
*result = Ok(0);
|
||||||
|
for update in updates.iter() {
|
||||||
|
let mut borrowed_account = question_mark!(
|
||||||
|
instruction_context
|
||||||
|
.try_borrow_instruction_account(
|
||||||
|
transaction_context,
|
||||||
|
update.instruction_account_index as usize,
|
||||||
|
)
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
let attribute =
|
||||||
|
unsafe { std::mem::transmute::<_, TransactionContextAttribute>(update.attribute) };
|
||||||
|
match attribute {
|
||||||
|
TransactionContextAttribute::TransactionAccountOwner => {
|
||||||
|
let owner_pubkey = question_mark!(
|
||||||
|
translate_type_mut::<Pubkey>(
|
||||||
|
memory_mapping,
|
||||||
|
update.value,
|
||||||
|
invoke_context.get_check_aligned()
|
||||||
|
),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
question_mark!(
|
||||||
|
borrowed_account
|
||||||
|
.set_owner(&owner_pubkey.to_bytes())
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TransactionContextAttribute::TransactionAccountLamports => question_mark!(
|
||||||
|
borrowed_account
|
||||||
|
.set_lamports(update.value)
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
),
|
||||||
|
TransactionContextAttribute::TransactionAccountData => question_mark!(
|
||||||
|
borrowed_account
|
||||||
|
.set_data_length(update.value as usize)
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
),
|
||||||
|
TransactionContextAttribute::TransactionAccountIsExecutable => question_mark!(
|
||||||
|
borrowed_account
|
||||||
|
.set_executable(update.value != 0)
|
||||||
|
.map_err(SyscallError::InstructionError),
|
||||||
|
result
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
*result = Err(SyscallError::InvalidAttribute.into());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
@ -3258,6 +3374,153 @@ mod tests {
|
||||||
assert_eq!(result, Ok(0));
|
assert_eq!(result, Ok(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_syscall_sol_set_account_properties() {
|
||||||
|
let program_key = Pubkey::new_unique();
|
||||||
|
let loader_key = bpf_loader::id();
|
||||||
|
let transaction_accounts = vec![
|
||||||
|
(
|
||||||
|
loader_key,
|
||||||
|
AccountSharedData::new(0, 0, &native_loader::id()),
|
||||||
|
),
|
||||||
|
(program_key, AccountSharedData::new(0, 0, &loader_key)),
|
||||||
|
(
|
||||||
|
Pubkey::new_unique(),
|
||||||
|
AccountSharedData::new(0, 0, &program_key),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pubkey::new_unique(),
|
||||||
|
AccountSharedData::new(0, 0, &program_key),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
let mut transaction_context =
|
||||||
|
TransactionContext::new(transaction_accounts, Some(Rent::default()), 1, 1);
|
||||||
|
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||||
|
invoke_context
|
||||||
|
.push(
|
||||||
|
&[
|
||||||
|
InstructionAccount {
|
||||||
|
index_in_transaction: 2,
|
||||||
|
index_in_caller: 2,
|
||||||
|
index_in_callee: 0,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
InstructionAccount {
|
||||||
|
index_in_transaction: 3,
|
||||||
|
index_in_caller: 3,
|
||||||
|
index_in_callee: 0,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
&[0, 1],
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let keys = [loader_key];
|
||||||
|
let updates_list = [
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: 0,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountLamports as u16,
|
||||||
|
value: 10000000,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
},
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: 0,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountData as u16,
|
||||||
|
value: 512,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
},
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: 0,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountIsExecutable as u16,
|
||||||
|
value: true as u64,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
},
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: 1,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountOwner as u16,
|
||||||
|
value: VM_ADDRESS_KEYS as u64,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let cost = invoke_context
|
||||||
|
.get_compute_budget()
|
||||||
|
.syscall_base_cost
|
||||||
|
.saturating_add(
|
||||||
|
invoke_context
|
||||||
|
.get_compute_budget()
|
||||||
|
.account_property_update_cost
|
||||||
|
.saturating_mul(updates_list.len() as u64),
|
||||||
|
);
|
||||||
|
let mut syscall_set_account_properties = SyscallSetAccountProperties {
|
||||||
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
|
};
|
||||||
|
const VM_ADDRESS_KEYS: u64 = 0x100000000;
|
||||||
|
const VM_ADDRESS_UPDATES_LIST: u64 = 0x200000000;
|
||||||
|
let config = Config::default();
|
||||||
|
let mut memory_mapping = MemoryMapping::new::<UserError>(
|
||||||
|
vec![
|
||||||
|
MemoryRegion::default(),
|
||||||
|
MemoryRegion {
|
||||||
|
host_addr: keys.as_ptr() as u64,
|
||||||
|
vm_addr: VM_ADDRESS_KEYS,
|
||||||
|
len: (keys.len() * std::mem::size_of::<Pubkey>()) as u64,
|
||||||
|
vm_gap_shift: 63,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
MemoryRegion {
|
||||||
|
host_addr: updates_list.as_ptr() as u64,
|
||||||
|
vm_addr: VM_ADDRESS_UPDATES_LIST,
|
||||||
|
len: (updates_list.len() * std::mem::size_of::<AccountPropertyUpdate>()) as u64,
|
||||||
|
vm_gap_shift: 63,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
&config,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
syscall_set_account_properties
|
||||||
|
.invoke_context
|
||||||
|
.borrow_mut()
|
||||||
|
.get_compute_meter()
|
||||||
|
.borrow_mut()
|
||||||
|
.mock_set_remaining(cost);
|
||||||
|
let mut result: Result<u64, EbpfError<BpfError>> = Ok(0);
|
||||||
|
syscall_set_account_properties.call(
|
||||||
|
VM_ADDRESS_UPDATES_LIST,
|
||||||
|
updates_list.len() as u64,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut memory_mapping,
|
||||||
|
&mut result,
|
||||||
|
);
|
||||||
|
assert_eq!(result, Ok(0));
|
||||||
|
{
|
||||||
|
let transaction_context = &syscall_set_account_properties
|
||||||
|
.invoke_context
|
||||||
|
.borrow()
|
||||||
|
.transaction_context;
|
||||||
|
let account = transaction_context
|
||||||
|
.get_account_at_index(2)
|
||||||
|
.unwrap()
|
||||||
|
.borrow();
|
||||||
|
assert_eq!(account.lamports(), 10000000);
|
||||||
|
assert_eq!(account.data().len(), 512);
|
||||||
|
assert!(account.executable());
|
||||||
|
let account = transaction_context
|
||||||
|
.get_account_at_index(3)
|
||||||
|
.unwrap()
|
||||||
|
.borrow();
|
||||||
|
assert_eq!(account.owner(), &loader_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_program_address() {
|
fn test_create_program_address() {
|
||||||
// These tests duplicate the direct tests in solana_program::pubkey
|
// These tests duplicate the direct tests in solana_program::pubkey
|
||||||
|
|
|
@ -739,6 +739,34 @@ pub fn get_stack_height() -> usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to specify which properties of which accounts to update
|
||||||
|
/// when calling the `sol_set_account_properties` syscall.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct AccountPropertyUpdate<'a> {
|
||||||
|
/// Index of the account to update
|
||||||
|
pub instruction_account_index: u16,
|
||||||
|
/// Index of the property to update
|
||||||
|
pub attribute: u16,
|
||||||
|
/// Value to set, encoding depends on the attribute
|
||||||
|
pub value: u64,
|
||||||
|
/// Holds the lifetime parameter in case that the value is a pointer
|
||||||
|
pub _marker: std::marker::PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets properties of accounts according to the given list of updates
|
||||||
|
pub fn set_account_properties(updates: &[AccountPropertyUpdate]) {
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
unsafe {
|
||||||
|
crate::syscalls::sol_set_account_properties(updates.as_ptr(), updates.len() as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "solana"))]
|
||||||
|
{
|
||||||
|
crate::program_stubs::sol_set_account_properties(updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_account_meta_layout() {
|
fn test_account_meta_layout() {
|
||||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction,
|
account_info::AccountInfo,
|
||||||
program_error::UNSUPPORTED_SYSVAR, pubkey::Pubkey,
|
entrypoint::ProgramResult,
|
||||||
|
instruction::{AccountPropertyUpdate, Instruction},
|
||||||
|
program_error::UNSUPPORTED_SYSVAR,
|
||||||
|
pubkey::Pubkey,
|
||||||
},
|
},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
|
@ -97,6 +100,7 @@ pub trait SyscallStubs: Sync + Send {
|
||||||
fn sol_get_stack_height(&self) -> u64 {
|
fn sol_get_stack_height(&self) -> u64 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
fn sol_set_account_properties(&self, _updates: &[AccountPropertyUpdate]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultSyscallStubs {}
|
struct DefaultSyscallStubs {}
|
||||||
|
@ -194,6 +198,13 @@ pub(crate) fn sol_get_stack_height() -> u64 {
|
||||||
SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
|
SYSCALL_STUBS.read().unwrap().sol_get_stack_height()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sol_set_account_properties(updates: &[AccountPropertyUpdate]) {
|
||||||
|
SYSCALL_STUBS
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.sol_set_account_properties(updates)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check that two regions do not overlap.
|
/// Check that two regions do not overlap.
|
||||||
///
|
///
|
||||||
/// Adapted from libcore, hidden to share with bpf_loader without being part of
|
/// Adapted from libcore, hidden to share with bpf_loader without being part of
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::{AccountMeta, ProcessedSiblingInstruction},
|
instruction::{AccountMeta, AccountPropertyUpdate, ProcessedSiblingInstruction},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ define_syscall!(fn sol_get_return_data(data: *mut u8, length: u64, program_id: *
|
||||||
define_syscall!(fn sol_log_data(data: *const u8, data_len: u64));
|
define_syscall!(fn sol_log_data(data: *const u8, data_len: u64));
|
||||||
define_syscall!(fn sol_get_processed_sibling_instruction(index: u64, meta: *mut ProcessedSiblingInstruction, program_id: *mut Pubkey, data: *mut u8, accounts: *mut AccountMeta) -> u64);
|
define_syscall!(fn sol_get_processed_sibling_instruction(index: u64, meta: *mut ProcessedSiblingInstruction, program_id: *mut Pubkey, data: *mut u8, accounts: *mut AccountMeta) -> u64);
|
||||||
define_syscall!(fn sol_get_stack_height() -> u64);
|
define_syscall!(fn sol_get_stack_height() -> u64);
|
||||||
|
define_syscall!(fn sol_set_account_properties(updates_addr: *const AccountPropertyUpdate, updates_count: u64));
|
||||||
define_syscall!(fn sol_curve_validate_point(curve_id: u64, point: *const u8, result: *mut u8) -> u64);
|
define_syscall!(fn sol_curve_validate_point(curve_id: u64, point: *const u8, result: *mut u8) -> u64);
|
||||||
define_syscall!(fn sol_curve_group_op(curve_id: u64, op_id: u64, left_point: *const u8, right_point: *const u8, result: *mut u8) -> u64);
|
define_syscall!(fn sol_curve_group_op(curve_id: u64, op_id: u64, left_point: *const u8, right_point: *const u8, result: *mut u8) -> u64);
|
||||||
define_syscall!(fn sol_curve_multiscalar_mul(curve_id: u64, scalars: *const u8, points: *const u8, result: *mut u8) -> u64);
|
define_syscall!(fn sol_curve_multiscalar_mul(curve_id: u64, scalars: *const u8, points: *const u8, result: *mut u8) -> u64);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Data shared between program runtime and built-in programs as well as SBF programs
|
//! Data shared between program runtime and built-in programs as well as SBF programs
|
||||||
|
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
use crate::instruction::AccountPropertyUpdate;
|
||||||
#[cfg(not(target_os = "solana"))]
|
#[cfg(not(target_os = "solana"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
account::WritableAccount,
|
account::WritableAccount,
|
||||||
|
@ -23,6 +25,59 @@ use {
|
||||||
|
|
||||||
pub type TransactionAccount = (Pubkey, AccountSharedData);
|
pub type TransactionAccount = (Pubkey, AccountSharedData);
|
||||||
|
|
||||||
|
/// For addressing (nested) properties of the TransactionContext
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum TransactionContextAttribute {
|
||||||
|
/// TransactionContext -> &[u8]
|
||||||
|
ReturnData,
|
||||||
|
/// TransactionContext -> u128
|
||||||
|
AccountsResizeDelta,
|
||||||
|
/// TransactionContext -> u16
|
||||||
|
TransactionAccountCount,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> Pubkey
|
||||||
|
TransactionAccountKey,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> Pubkey
|
||||||
|
TransactionAccountOwner,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> u64
|
||||||
|
TransactionAccountLamports,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> &[u8]
|
||||||
|
TransactionAccountData,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> bool
|
||||||
|
TransactionAccountIsExecutable,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> u64
|
||||||
|
TransactionAccountRentEpoch,
|
||||||
|
/// TransactionContext -> &[TransactionAccount] -> bool
|
||||||
|
TransactionAccountTouchedFlag,
|
||||||
|
/// TransactionContext -> u8
|
||||||
|
InstructionStackHeight,
|
||||||
|
/// TransactionContext -> u8
|
||||||
|
InstructionStackCapacity,
|
||||||
|
/// TransactionContext -> &[u8]
|
||||||
|
InstructionStackEntry,
|
||||||
|
/// TransactionContext -> u16
|
||||||
|
InstructionTraceLength,
|
||||||
|
/// TransactionContext -> u16
|
||||||
|
InstructionTraceCapacity,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> u8
|
||||||
|
InstructionTraceNestingLevel,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> u128
|
||||||
|
InstructionTraceLamportSum,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[u8]
|
||||||
|
InstructionTraceInstructionData,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[u16]
|
||||||
|
InstructionTraceProgramAccount,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[InstructionAccount] -> u16
|
||||||
|
InstructionAccountIndexInTransaction,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[InstructionAccount] -> u16
|
||||||
|
InstructionAccountIndexInCaller,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[InstructionAccount] -> u16
|
||||||
|
InstructionAccountIndexInCallee,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[InstructionAccount] -> bool
|
||||||
|
InstructionAccountIsSigner,
|
||||||
|
/// TransactionContext -> &[InstructionContext] -> &[InstructionAccount] -> bool
|
||||||
|
InstructionAccountIsWritable,
|
||||||
|
}
|
||||||
|
|
||||||
/// Contains account meta data which varies between instruction.
|
/// Contains account meta data which varies between instruction.
|
||||||
///
|
///
|
||||||
/// It also contains indices to other structures for faster lookup.
|
/// It also contains indices to other structures for faster lookup.
|
||||||
|
@ -657,6 +712,16 @@ impl<'a> BorrowedAccount<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
pub fn set_owner<'b>(&mut self, pubkey: &'b [u8]) -> AccountPropertyUpdate<'b> {
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: self.index_in_instruction as u16,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountOwner as u16,
|
||||||
|
value: pubkey.as_ptr() as u64,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of lamports of this account (transaction wide)
|
/// Returns the number of lamports of this account (transaction wide)
|
||||||
pub fn get_lamports(&self) -> u64 {
|
pub fn get_lamports(&self) -> u64 {
|
||||||
self.account.lamports()
|
self.account.lamports()
|
||||||
|
@ -691,6 +756,16 @@ impl<'a> BorrowedAccount<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
pub fn set_lamports(&mut self, lamports: u64) -> AccountPropertyUpdate<'static> {
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: self.index_in_instruction as u16,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountLamports as u16,
|
||||||
|
value: lamports,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds lamports to this account (transaction wide)
|
/// Adds lamports to this account (transaction wide)
|
||||||
#[cfg(not(target_os = "solana"))]
|
#[cfg(not(target_os = "solana"))]
|
||||||
pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
||||||
|
@ -768,6 +843,16 @@ impl<'a> BorrowedAccount<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
pub fn set_data_length(&mut self, new_length: usize) -> AccountPropertyUpdate<'static> {
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: self.index_in_instruction as u16,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountData as u16,
|
||||||
|
value: new_length as u64,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Deserializes the account data into a state
|
/// Deserializes the account data into a state
|
||||||
#[cfg(not(target_os = "solana"))]
|
#[cfg(not(target_os = "solana"))]
|
||||||
pub fn get_state<T: serde::de::DeserializeOwned>(&self) -> Result<T, InstructionError> {
|
pub fn get_state<T: serde::de::DeserializeOwned>(&self) -> Result<T, InstructionError> {
|
||||||
|
@ -824,6 +909,16 @@ impl<'a> BorrowedAccount<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "solana")]
|
||||||
|
pub fn set_executable(&mut self, is_executable: bool) -> AccountPropertyUpdate<'static> {
|
||||||
|
AccountPropertyUpdate {
|
||||||
|
instruction_account_index: self.index_in_instruction as u16,
|
||||||
|
attribute: TransactionContextAttribute::TransactionAccountIsExecutable as u16,
|
||||||
|
value: is_executable as u64,
|
||||||
|
_marker: std::marker::PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the rent epoch of this account (transaction wide)
|
/// Returns the rent epoch of this account (transaction wide)
|
||||||
#[cfg(not(target_os = "solana"))]
|
#[cfg(not(target_os = "solana"))]
|
||||||
pub fn get_rent_epoch(&self) -> u64 {
|
pub fn get_rent_epoch(&self) -> u64 {
|
||||||
|
|
Loading…
Reference in New Issue