BPF rust language updates (#4752)

This commit is contained in:
Jack May
2019-06-20 16:07:12 -07:00
committed by GitHub
parent aacb38864c
commit e59b53dfa8
21 changed files with 230 additions and 180 deletions

View File

@ -1,24 +1,17 @@
//! @brief Solana Rust-based BPF program entrypoint and its parameter types
extern crate alloc;
use crate::log::*;
use alloc::vec::Vec;
use core::mem::size_of;
use core::slice::{from_raw_parts, from_raw_parts_mut};
/// Max number of accounts supported
pub const MAX_ACCOUNTS: usize = 10;
/// Size in bytes of a public key
pub const SIZE_PUBKEY: usize = 32;
/// Public key
pub struct SolPubkey<'a> {
pub key: &'a [u8; SIZE_PUBKEY],
}
pub type SolPubkey = [u8; 32];
/// Keyed Account
pub struct SolKeyedAccount<'a> {
/// Public key of the account
pub key: SolPubkey<'a>,
pub key: &'a SolPubkey,
/// Public key of the account
pub is_signer: bool,
/// Number of lamports owned by this account
@ -26,14 +19,14 @@ pub struct SolKeyedAccount<'a> {
/// On-chain data within this account
pub data: &'a mut [u8],
/// Program that owns this account
pub owner: SolPubkey<'a>,
pub owner: &'a SolPubkey,
}
/// Information about the state of the cluster immediately before the program
/// started executing the current instruction
pub struct SolClusterInfo<'a> {
///program_id of the currently executing program
pub program_id: SolPubkey<'a>,
/// program_id of the currently executing program
pub program_id: &'a SolPubkey,
}
/// Declare entrypoint of the program.
@ -48,9 +41,8 @@ macro_rules! entrypoint {
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> bool {
unsafe {
if let Ok((mut ka, info, data)) = $crate::entrypoint::deserialize(input) {
// Call use function
$process_instruction(&mut ka, &info, &data)
if let Ok((mut kas, info, data)) = $crate::entrypoint::deserialize(input) {
$process_instruction(&mut kas, &info, &data)
} else {
false
}
@ -63,32 +55,19 @@ macro_rules! entrypoint {
#[allow(clippy::type_complexity)]
pub unsafe fn deserialize<'a>(
input: *mut u8,
) -> Result<
(
[Option<SolKeyedAccount<'a>>; MAX_ACCOUNTS],
SolClusterInfo<'a>,
&'a [u8],
),
(),
> {
) -> Result<(Vec<SolKeyedAccount<'a>>, SolClusterInfo<'a>, &'a [u8]), ()> {
let mut offset: usize = 0;
// Number of KeyedAccounts present
#[allow(clippy::cast_ptr_alignment)]
let num_ka = *(input.add(offset) as *const u64) as usize;
offset += 8;
offset += size_of::<u64>();
// KeyedAccounts
if num_ka > MAX_ACCOUNTS {
sol_log("Error: Too many accounts");
return Err(());
}
let mut kas: [Option<SolKeyedAccount>; MAX_ACCOUNTS] =
[None, None, None, None, None, None, None, None, None, None];
for ka in kas.iter_mut().take(num_ka) {
let mut kas = Vec::new();
for _ in 0..num_ka {
let is_signer = {
#[allow(clippy::cast_ptr_alignment)]
let is_signer_val = *(input.add(offset) as *const u64);
@ -96,12 +75,8 @@ pub unsafe fn deserialize<'a>(
};
offset += size_of::<u64>();
let key = {
SolPubkey {
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
}
};
offset += SIZE_PUBKEY;
let key: &SolPubkey = &*(input.add(offset) as *const [u8; size_of::<SolPubkey>()]);
offset += size_of::<SolPubkey>();
#[allow(clippy::cast_ptr_alignment)]
let lamports = *(input.add(offset) as *const u64);
@ -114,14 +89,10 @@ pub unsafe fn deserialize<'a>(
let data = { from_raw_parts_mut(input.add(offset), data_length) };
offset += data_length;
let owner = {
SolPubkey {
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
}
};
offset += SIZE_PUBKEY;
let owner: &SolPubkey = &*(input.add(offset) as *const [u8; size_of::<SolPubkey>()]);
offset += size_of::<SolPubkey>();
*ka = Some(SolKeyedAccount {
kas.push(SolKeyedAccount {
key,
is_signer,
lamports,
@ -139,14 +110,9 @@ pub unsafe fn deserialize<'a>(
let data = { from_raw_parts(input.add(offset), data_length) };
offset += data_length;
// Id
let program_id = {
SolPubkey {
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
}
};
// Program Id
let program_id: &SolPubkey = &*(input.add(offset) as *const [u8; size_of::<SolPubkey>()]);
let info = SolClusterInfo { program_id };
Ok((kas, info, data))

View File

@ -6,7 +6,8 @@
#![feature(panic_info_message)]
#![feature(compiler_builtins_lib)]
#![feature(lang_items)]
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
extern crate compiler_builtins;

View File

@ -2,13 +2,37 @@
use crate::entrypoint::{SolKeyedAccount, SolPubkey};
/// Prints a string
/// There are two forms and are fast
/// 1. Single string
/// 2. 5 integers
#[macro_export]
macro_rules! info {
($msg:expr) => {
$crate::log::sol_log($msg)
};
($arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => {
$crate::log::sol_log_64(
$arg1 as u64,
$arg2 as u64,
$arg3 as u64,
$arg4 as u64,
$arg5 as u64,
)
}; // `format!()` is not supported yet, Issue #3099
// `format!()` incurs a very large runtime overhead so it should be used with care
// ($($arg:tt)*) => ($crate::log::sol_log(&format!($($arg)*)));
}
/// Prints a string to stdout
#[inline(never)] // stack intensive, prevent inline so everyone does not incur cost
///
/// @param message - Message to print
#[inline(never)] // prevent inline so everyone does not incur stack cost
pub fn sol_log(message: &str) {
// TODO This is extremely slow, do something better
// Not pretty but 1/3 faster then using `clone_from_slice()`
let mut buf: [u8; 128] = [0; 128];
for (i, b) in message.as_bytes().iter().enumerate() {
if i >= 126 {
if i > 127 {
break;
}
buf[i] = *b;
@ -22,6 +46,8 @@ extern "C" {
}
/// Prints 64 bit values represented as hexadecimal to stdout
///
/// @param argx - integer arguments to print
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
unsafe {
sol_log_64_(arg1, arg2, arg3, arg4, arg5);
@ -36,7 +62,7 @@ extern "C" {
/// @param - key The public key to print
#[allow(dead_code)]
pub fn sol_log_key(key: &SolPubkey) {
for (i, k) in key.key.iter().enumerate() {
for (i, k) in key.iter().enumerate() {
sol_log_64(0, 0, 0, i as u64, u64::from(*k));
}
}
@ -56,22 +82,20 @@ pub fn sol_log_slice(slice: &[u8]) {
/// @param ka - A pointer to an array of `SolKeyedAccounts` to print
/// @param data - A pointer to the instruction data to print
#[allow(dead_code)]
pub fn sol_log_params(ka: &[Option<SolKeyedAccount>], data: &[u8]) {
pub fn sol_log_params(ka: &[SolKeyedAccount], data: &[u8]) {
for (i, k) in ka.iter().enumerate() {
if let Some(k) = k {
sol_log("SolKeyedAccount");
sol_log_64(0, 0, 0, 0, i as u64);
sol_log("- Is signer");
sol_log_64(0, 0, 0, 0, k.is_signer as u64);
sol_log("- Key");
sol_log_key(&k.key);
sol_log("- Lamports");
sol_log_64(0, 0, 0, 0, k.lamports);
sol_log("- AccountData");
sol_log_slice(k.data);
sol_log("- Owner");
sol_log_key(&k.owner);
}
sol_log("SolKeyedAccount");
sol_log_64(0, 0, 0, 0, i as u64);
sol_log("- Is signer");
sol_log_64(0, 0, 0, 0, k.is_signer as u64);
sol_log("- Key");
sol_log_key(&k.key);
sol_log("- Lamports");
sol_log_64(0, 0, 0, 0, k.lamports);
sol_log("- AccountData");
sol_log_slice(k.data);
sol_log("- Owner");
sol_log_key(&k.owner);
}
sol_log("Instruction data");
sol_log_slice(data);

View File

@ -6,11 +6,12 @@ use core::ptr;
#[cfg(not(test))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
// Message is ignored for now to avoid incurring formatting program size overhead
match info.location() {
Some(location) => {
let mut file: [u8; 128] = [0; 128];
for (i, c) in location.file().as_bytes().iter().enumerate() {
if i >= 126 {
if i > 127 {
break;
}
file[i] = *c;