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

@ -10,14 +10,22 @@ source ci/rust-version.sh nightly
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings" export RUSTFLAGS="-D warnings"
( do_bpf_check() {
for project in programs/bpf/rust/*/ ; do
(
cd "$project"
_ cargo +"$rust_stable" fmt --all -- --check _ cargo +"$rust_stable" fmt --all -- --check
_ cargo +"$rust_nightly" clippy --all -- --version _ cargo +"$rust_nightly" clippy --all -- --version
_ cargo +"$rust_nightly" clippy --all -- --deny=warnings _ cargo +"$rust_nightly" clippy --all -- --deny=warnings
_ cargo +"$rust_stable" audit _ cargo +"$rust_stable" audit
}
(
(
cd sdk/bpf/rust/rust-utils
do_bpf_check
)
for project in programs/bpf/rust/*/ ; do
(
cd "$project"
do_bpf_check
) )
done done
) )

View File

@ -81,8 +81,9 @@ fn main() {
"cargo:warning=(not a warning) Building Rust-based BPF programs: solana_bpf_rust_{}", "cargo:warning=(not a warning) Building Rust-based BPF programs: solana_bpf_rust_{}",
program program
); );
assert!(Command::new("./build.sh") assert!(Command::new("./do.sh")
.current_dir("rust") .current_dir("rust")
.arg("build")
.arg(program) .arg(program)
.status() .status()
.expect(&format!( .expect(&format!(

View File

@ -6,11 +6,10 @@
extern crate alloc; extern crate alloc;
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use solana_sdk_bpf_utils::log::*;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::alloc::Layout; use core::alloc::Layout;
use core::mem; use core::mem;
use solana_sdk_bpf_utils::info;
#[no_mangle] #[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> bool { pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
@ -20,7 +19,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
let layout = Layout::from_size_align(core::usize::MAX, mem::align_of::<u8>()).unwrap(); let layout = Layout::from_size_align(core::usize::MAX, mem::align_of::<u8>()).unwrap();
let ptr = alloc::alloc::alloc(layout); let ptr = alloc::alloc::alloc(layout);
if !ptr.is_null() { if !ptr.is_null() {
sol_log("Error: Alloc of very larger buffer should fail"); info!("Error: Alloc of very larger buffer should fail");
panic!(); panic!();
} }
} }
@ -31,7 +30,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
let layout = Layout::from_size_align(100, mem::align_of::<u8>()).unwrap(); let layout = Layout::from_size_align(100, mem::align_of::<u8>()).unwrap();
let ptr = alloc::alloc::alloc(layout); let ptr = alloc::alloc::alloc(layout);
if ptr.is_null() { if ptr.is_null() {
sol_log("Error: Alloc of 100 bytes failed"); info!("Error: Alloc of 100 bytes failed");
alloc::alloc::handle_alloc_error(layout); alloc::alloc::handle_alloc_error(layout);
} }
alloc::alloc::dealloc(ptr, layout); alloc::alloc::dealloc(ptr, layout);
@ -44,7 +43,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
let layout = Layout::from_size_align(100, mem::align_of::<u8>()).unwrap(); let layout = Layout::from_size_align(100, mem::align_of::<u8>()).unwrap();
let ptr = alloc::alloc::alloc(layout); let ptr = alloc::alloc::alloc(layout);
if ptr.is_null() { if ptr.is_null() {
sol_log("Error: Alloc failed"); info!("Error: Alloc failed");
alloc::alloc::handle_alloc_error(layout); alloc::alloc::handle_alloc_error(layout);
} }
for i in 0..ITERS { for i in 0..ITERS {
@ -53,7 +52,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
for i in 0..ITERS { for i in 0..ITERS {
assert_eq!(*ptr.add(i as usize), i as u8); assert_eq!(*ptr.add(i as usize), i as u8);
} }
sol_log_64(0x3, 0, 0, 0, u64::from(*ptr.add(42))); info!(0x3, 0, 0, 0, u64::from(*ptr.add(42)));
assert_eq!(*ptr.add(42), 42); assert_eq!(*ptr.add(42), 42);
alloc::alloc::dealloc(ptr, layout); alloc::alloc::dealloc(ptr, layout);
} }
@ -65,13 +64,13 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
// let layout = Layout::from_size_align(2048, mem::align_of::<u8>()).unwrap(); // let layout = Layout::from_size_align(2048, mem::align_of::<u8>()).unwrap();
// let ptr = alloc::alloc::alloc(layout); // let ptr = alloc::alloc::alloc(layout);
// if ptr.is_null() { // if ptr.is_null() {
// sol_log("Error: Alloc of 2048 bytes failed"); // info!("Error: Alloc of 2048 bytes failed");
// alloc::alloc::handle_alloc_error(layout); // alloc::alloc::handle_alloc_error(layout);
// } // }
// let layout = Layout::from_size_align(1, mem::align_of::<u8>()).unwrap(); // let layout = Layout::from_size_align(1, mem::align_of::<u8>()).unwrap();
// let ptr_fail = alloc::alloc::alloc(layout); // let ptr_fail = alloc::alloc::alloc(layout);
// if !ptr_fail.is_null() { // if !ptr_fail.is_null() {
// sol_log("Error: Able to alloc 1 more then max"); // info!("Error: Able to alloc 1 more then max");
// panic!(); // panic!();
// } // }
// alloc::alloc::dealloc(ptr, layout); // alloc::alloc::dealloc(ptr, layout);
@ -87,7 +86,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
for v in ones.iter() { for v in ones.iter() {
sum += ones[*v]; sum += ones[*v];
} }
sol_log_64(0x0, 0, 0, 0, sum as u64); info!(0x0, 0, 0, 0, sum as u64);
assert_eq!(sum, ITERS); assert_eq!(sum, ITERS);
} }
@ -98,13 +97,12 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
let mut v = Vec::new(); let mut v = Vec::new();
for i in 0..ITERS { for i in 0..ITERS {
sol_log_64(i as u64, 0, 0, 0, 0);
v.push(i); v.push(i);
} }
sol_log_64(0x4, 0, 0, 0, v.len() as u64); info!(0x4, 0, 0, 0, v.len() as u64);
assert_eq!(v.len(), ITERS); assert_eq!(v.len(), ITERS);
} }
sol_log("Success"); info!("Success");
true true
} }

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
# Build all projects
for project in */ ; do
./../../../sdk/bpf/rust/build.sh "$PWD/$project"
done
else
# Build requested project
./../../../sdk/bpf/rust/build.sh "$PWD/$1"
fi

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
# Clean all projects
for project in */ ; do
./../../../sdk/bpf/rust/clean.sh "$PWD/$project"
done
else
# Clean requested project
./../../../sdk/bpf/rust/clean.sh "$PWD/$1"
fi

View File

@ -6,7 +6,7 @@
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::info;
#[no_mangle] #[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> bool { pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
@ -18,6 +18,6 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
LittleEndian::write_i16(&mut buf, -5_000); LittleEndian::write_i16(&mut buf, -5_000);
assert_eq!(-5_000, LittleEndian::read_i16(&buf)); assert_eq!(-5_000, LittleEndian::read_i16(&buf));
sol_log("Success"); info!("Success");
true true
} }

100
programs/bpf/rust/do.sh Executable file
View File

@ -0,0 +1,100 @@
#!/usr/bin/env bash
usage() {
echo ""
echo " Usage: do.sh action <project>"
echo ""
echo " If relative_project_path is ommitted then action will"
echo " be performed on all projects"
echo ""
echo " Supported actions:"
echo " build"
echo " clean"
echo " clippy"
echo " fmt"
echo ""
}
perform_action() {
set -e
case "$1" in
build)
./../../../sdk/bpf/rust/build.sh "$2"
;;
clean)
./../../../sdk/bpf/rust/clean.sh "$2"
;;
clippy)
(
cd "$2"
echo "clippy $2"
cargo +nightly clippy
)
;;
fmt)
(
cd "$2"
echo "formatting $2"
cargo fmt
)
;;
dump)
# Dump depends on tools that are not installed by default and must be installed manually
# - greadelf
# - llvm-objdump
# - rustfilt
(
pwd
./do.sh clean "$3"
./do.sh build "$3"
cd "$3"
set +e
cp ./target/dump.txt ./targetdump-last.txt 2>/dev/null
set -e
ls \
-la \
./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${3%/}".so \
> ./target/dump_mangled.txt
greadelf \
-aW \
./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${3%/}".so \
>> ./target/dump_mangled.txt
llvm-objdump \
-print-imm-hex \
--source \
--disassemble \
./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${3%/}".so \
>> ./target/dump_mangled.txt
sed \
s/://g \
< ./target/dump_mangled.txt \
| rustfilt \
> ./target/dump.txt
)
;;
help)
usage
exit
;;
*)
echo "Error: Unknown command"
usage
exit
;;
esac
}
set -e
if [ "$#" -ne 2 ]; then
# Build all projects
for project in */ ; do
perform_action "$1" "$PWD/$project" "$project"
done
else
# Build requested project
perform_action "$1" "$PWD/$2" "$2"
fi

View File

@ -1,21 +0,0 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Error: Must provide the name of the project to dump"
exit 1
fi
./clean.sh "$1"
./build.sh "$1"
cd "$1"
cp ./target/dump.txt ./targetdump-last.txt 2>/dev/null
set -ex
ls -la ./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${1%/}".so > ./target/dump_mangled.txt
greadelf -aW ./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${1%/}".so >> ./target/dump_mangled.txt
llvm-objdump -print-imm-hex --source --disassemble ./target/bpfel-unknown-unknown/release/solana_bpf_rust_"${1%/}".so >> ./target/dump_mangled.txt
sed s/://g < ./target/dump_mangled.txt | rustfilt > ./target/dump.txt

View File

@ -5,7 +5,7 @@
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::info;
#[no_mangle] #[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> bool { pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
@ -16,9 +16,9 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
for v in ones.iter() { for v in ones.iter() {
sum += *v; sum += *v;
} }
sol_log_64(0xff, 0, 0, 0, sum); info!(0xff, 0, 0, 0, sum);
assert_eq!(sum, ITERS as u64); assert_eq!(sum, ITERS as u64);
sol_log("Success"); info!("Success");
true true
} }

View File

@ -7,18 +7,18 @@ mod helper;
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::info;
#[no_mangle] #[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> bool { pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
sol_log("call same package"); info!("call same package");
assert_eq!(crate::helper::many_args(1, 2, 3, 4, 5, 6, 7, 8, 9), 45); assert_eq!(crate::helper::many_args(1, 2, 3, 4, 5, 6, 7, 8, 9), 45);
sol_log("call another package"); info!("call another package");
assert_eq!( assert_eq!(
solana_bpf_rust_many_args_dep::many_args(1, 2, 3, 4, 5, 6, 7, 8, 9), solana_bpf_rust_many_args_dep::many_args(1, 2, 3, 4, 5, 6, 7, 8, 9),
45 45
); );
sol_log("Success"); info!("Success");
true true
} }

View File

@ -0,0 +1,6 @@
[dependencies.compiler_builtins]
path = "../../../../sdk/bpf/dependencies/rust-bpf-sysroot/src/compiler-builtins"
features = ["c", "mem"]
[target.bpfel-unknown-unknown.dependencies]
alloc = { path = "../../../../sdk/bpf/dependencies/rust-bpf-sysroot/src/liballoc" }

View File

@ -4,7 +4,7 @@
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::info;
pub fn many_args( pub fn many_args(
arg1: u64, arg1: u64,
@ -17,8 +17,8 @@ pub fn many_args(
arg8: u64, arg8: u64,
arg9: u64, arg9: u64,
) -> u64 { ) -> u64 {
sol_log("another package"); info!("another package");
sol_log_64(arg1, arg2, arg3, arg4, arg5); info!(arg1, arg2, arg3, arg4, arg5);
sol_log_64(arg6, arg7, arg8, arg9, 0); info!(arg6, arg7, arg8, arg9, 0);
arg1 + arg2 + arg3 + arg4 + arg5 + arg6 + arg7 + arg8 + arg9 arg1 + arg2 + arg3 + arg4 + arg5 + arg6 + arg7 + arg8 + arg9
} }

View File

@ -2,12 +2,13 @@
#![no_std] #![no_std]
#![allow(unreachable_code)] #![allow(unreachable_code)]
#![allow(unused_attributes)]
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use solana_sdk_bpf_utils::entrypoint;
use solana_sdk_bpf_utils::entrypoint::*; use solana_sdk_bpf_utils::entrypoint::*;
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::log::*;
use solana_sdk_bpf_utils::{entrypoint, info};
struct SStruct { struct SStruct {
x: u64, x: u64,
@ -21,18 +22,14 @@ fn return_sstruct() -> SStruct {
} }
entrypoint!(process_instruction); entrypoint!(process_instruction);
fn process_instruction( fn process_instruction(ka: &mut [SolKeyedAccount], info: &SolClusterInfo, data: &[u8]) -> bool {
ka: &mut [Option<SolKeyedAccount>; MAX_ACCOUNTS], info!("Program identifier:");
info: &SolClusterInfo,
data: &[u8],
) -> bool {
sol_log("Program identifier:");
sol_log_key(&info.program_id); sol_log_key(&info.program_id);
// Log the provided account keys and instruction input data. In the case of // Log the provided account keys and instruction input data. In the case of
// the no-op program, no account keys or input data are expected but real // the no-op program, no account keys or input data are expected but real
// programs will have specific requirements so they can do their work. // programs will have specific requirements so they can do their work.
sol_log("Account keys and instruction input data:"); info!("Account keys and instruction input data:");
sol_log_params(ka, data); sol_log_params(ka, data);
{ {
@ -49,7 +46,7 @@ fn process_instruction(
let result_str = core::str::from_utf8(&sparkle_heart).unwrap(); let result_str = core::str::from_utf8(&sparkle_heart).unwrap();
assert_eq!(4, result_str.len()); assert_eq!(4, result_str.len());
assert_eq!("💖", result_str); assert_eq!("💖", result_str);
sol_log(result_str); info!(result_str);
} }
{ {
@ -59,6 +56,6 @@ fn process_instruction(
assert_eq!(s.x + s.y + s.z, 6); assert_eq!(s.x + s.y + s.z, 6);
} }
sol_log("Success"); info!("Success");
true true
} }

View File

@ -6,22 +6,14 @@
extern crate solana_sdk_bpf_utils; extern crate solana_sdk_bpf_utils;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use solana_sdk_bpf_utils::entrypoint;
use solana_sdk_bpf_utils::entrypoint::*; use solana_sdk_bpf_utils::entrypoint::*;
use solana_sdk_bpf_utils::log::*; use solana_sdk_bpf_utils::{entrypoint, info};
entrypoint!(process_instruction); entrypoint!(process_instruction);
fn process_instruction( fn process_instruction(ka: &mut [SolKeyedAccount], _info: &SolClusterInfo, _data: &[u8]) -> bool {
ka: &mut [Option<SolKeyedAccount>; MAX_ACCOUNTS], let tick_height = LittleEndian::read_u64(ka[2].data);
_info: &SolClusterInfo,
_data: &[u8],
) -> bool {
sol_log("Tick Height:");
if let Some(k) = &ka[2] {
let tick_height = LittleEndian::read_u64(k.data);
assert_eq!(10u64, tick_height); assert_eq!(10u64, tick_height);
sol_log("Success");
return true; info!("Success");
} true
panic!();
} }

View File

@ -87,10 +87,10 @@ mod bpf {
let programs = [ let programs = [
("solana_bpf_rust_alloc", true), ("solana_bpf_rust_alloc", true),
("solana_bpf_rust_dep_crate", true),
("solana_bpf_rust_iter", true), ("solana_bpf_rust_iter", true),
// ("solana_bpf_rust_many_args", true), // Issue #3099 // ("solana_bpf_rust_many_args", true), // Issue #3099
("solana_bpf_rust_noop", true), ("solana_bpf_rust_noop", true),
("solana_bpf_rust_dep_crate", true),
("solana_bpf_rust_panic", false), ("solana_bpf_rust_panic", false),
("solana_bpf_rust_tick_height", true), ("solana_bpf_rust_tick_height", true),
]; ];

View File

@ -164,7 +164,7 @@ pub fn helper_sol_log(
let c_buf: *const c_char = addr as *const c_char; let c_buf: *const c_char = addr as *const c_char;
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) }; let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
match c_str.to_str() { match c_str.to_str() {
Ok(slice) => info!("sol_log: {:?}", slice), Ok(slice) => info!("info!: {:?}", slice),
Err(e) => warn!("Error: Cannot print invalid string: {}", e), Err(e) => warn!("Error: Cannot print invalid string: {}", e),
}; };
0 0
@ -178,7 +178,7 @@ pub fn helper_sol_log_u64(
_context: &mut Option<Box<Any + 'static>>, _context: &mut Option<Box<Any + 'static>>,
) -> u64 { ) -> u64 {
info!( info!(
"sol_log_u64: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", "info!: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
arg1, arg2, arg3, arg4, arg5 arg1, arg2, arg3, arg4, arg5
); );
0 0

View File

@ -9,6 +9,8 @@ if [ ! -f "$1/Cargo.toml" ]; then
exit 1 exit 1
fi fi
echo "Building $1"
pushd "$(dirname "$0")" pushd "$(dirname "$0")"
bpf_sdk="$PWD/.." bpf_sdk="$PWD/.."
popd popd
@ -28,7 +30,6 @@ export AR="$bpf_sdk/dependencies/llvm-native/bin/llvm-ar"
# Use the SDK's version of Rust to build for BPF # Use the SDK's version of Rust to build for BPF
export RUSTUP_TOOLCHAIN=bpf export RUSTUP_TOOLCHAIN=bpf
export RUSTFLAGS=" export RUSTFLAGS="
--emit=llvm-ir \
-C lto=no \ -C lto=no \
-C opt-level=2 \ -C opt-level=2 \
-C link-arg=-z -C link-arg=notext \ -C link-arg=-z -C link-arg=notext \
@ -39,6 +40,6 @@ export RUSTFLAGS="
-C linker=$bpf_sdk/dependencies/llvm-native/bin/ld.lld" -C linker=$bpf_sdk/dependencies/llvm-native/bin/ld.lld"
export XARGO_HOME="$bpf_sdk/dependencies/xargo" export XARGO_HOME="$bpf_sdk/dependencies/xargo"
export XARGO_RUST_SRC="$bpf_sdk/dependencies/rust-bpf-sysroot/src" export XARGO_RUST_SRC="$bpf_sdk/dependencies/rust-bpf-sysroot/src"
xargo build --target bpfel-unknown-unknown --release -v xargo build --target bpfel-unknown-unknown --release
{ { set +x; } 2>/dev/null; echo Success; } { { set +x; } 2>/dev/null; echo Success; }

View File

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

View File

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

View File

@ -2,13 +2,37 @@
use crate::entrypoint::{SolKeyedAccount, SolPubkey}; 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 /// 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) { 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]; let mut buf: [u8; 128] = [0; 128];
for (i, b) in message.as_bytes().iter().enumerate() { for (i, b) in message.as_bytes().iter().enumerate() {
if i >= 126 { if i > 127 {
break; break;
} }
buf[i] = *b; buf[i] = *b;
@ -22,6 +46,8 @@ extern "C" {
} }
/// Prints 64 bit values represented as hexadecimal to stdout /// 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) { pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
unsafe { unsafe {
sol_log_64_(arg1, arg2, arg3, arg4, arg5); sol_log_64_(arg1, arg2, arg3, arg4, arg5);
@ -36,7 +62,7 @@ extern "C" {
/// @param - key The public key to print /// @param - key The public key to print
#[allow(dead_code)] #[allow(dead_code)]
pub fn sol_log_key(key: &SolPubkey) { 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)); sol_log_64(0, 0, 0, i as u64, u64::from(*k));
} }
} }
@ -56,9 +82,8 @@ pub fn sol_log_slice(slice: &[u8]) {
/// @param ka - A pointer to an array of `SolKeyedAccounts` to print /// @param ka - A pointer to an array of `SolKeyedAccounts` to print
/// @param data - A pointer to the instruction data to print /// @param data - A pointer to the instruction data to print
#[allow(dead_code)] #[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() { for (i, k) in ka.iter().enumerate() {
if let Some(k) = k {
sol_log("SolKeyedAccount"); sol_log("SolKeyedAccount");
sol_log_64(0, 0, 0, 0, i as u64); sol_log_64(0, 0, 0, 0, i as u64);
sol_log("- Is signer"); sol_log("- Is signer");
@ -72,7 +97,6 @@ pub fn sol_log_params(ka: &[Option<SolKeyedAccount>], data: &[u8]) {
sol_log("- Owner"); sol_log("- Owner");
sol_log_key(&k.owner); sol_log_key(&k.owner);
} }
}
sol_log("Instruction data"); sol_log("Instruction data");
sol_log_slice(data); sol_log_slice(data);
} }

View File

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