Common Rust-BPF utilities and types (#4325)
This commit is contained in:
parent
b2ce5dc9f5
commit
bc74ee7117
|
@ -9,11 +9,10 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
# byteorder = { version = "1.3.1", default-features = false }
|
||||
# heapless = { version = "0.4.0", default-features = false }
|
||||
# byte = { version = "0.2", default-features = false }
|
||||
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust-utils", version = "0.15.0" }
|
||||
|
||||
[workspace]
|
||||
members = []
|
||||
|
@ -21,5 +20,3 @@ members = []
|
|||
[lib]
|
||||
name = "solana_bpf_rust_noop"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//! @brief Example Rust-based BPF program that prints out the parameters passed to it
|
||||
|
||||
#![cfg(not(test))]
|
||||
#![no_std]
|
||||
|
||||
mod solana_sdk;
|
||||
extern crate solana_sdk_bpf_utils;
|
||||
|
||||
use solana_sdk::*;
|
||||
use solana_sdk_bpf_utils::*;
|
||||
|
||||
struct SStruct {
|
||||
x: u64,
|
||||
|
@ -18,7 +17,12 @@ fn return_sstruct() -> SStruct {
|
|||
SStruct { x: 1, y: 2, z: 3 }
|
||||
}
|
||||
|
||||
fn process(ka: &mut [SolKeyedAccount], data: &[u8], info: &SolClusterInfo) -> bool {
|
||||
solana_entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
ka: &mut [Option<SolKeyedAccount>; MAX_ACCOUNTS],
|
||||
info: &SolClusterInfo,
|
||||
data: &[u8],
|
||||
) -> bool {
|
||||
sol_log("Tick height:");
|
||||
sol_log_64(info.tick_height, 0, 0, 0, 0);
|
||||
sol_log("Program identifier:");
|
||||
|
@ -30,23 +34,27 @@ fn process(ka: &mut [SolKeyedAccount], data: &[u8], info: &SolClusterInfo) -> bo
|
|||
sol_log("Account keys and instruction input data:");
|
||||
sol_log_params(ka, data);
|
||||
|
||||
{
|
||||
// Test - arch config
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
assert!(false);
|
||||
}
|
||||
|
||||
{
|
||||
// Test - use core methods, unwrap
|
||||
|
||||
// valid bytes, in a stack-allocated array
|
||||
let sparkle_heart = [240, 159, 146, 150];
|
||||
|
||||
let result_str = core::str::from_utf8(&sparkle_heart).unwrap();
|
||||
|
||||
sol_log_64(0, 0, 0, 0, result_str.len() as u64);
|
||||
sol_log(result_str);
|
||||
assert_eq!(4, result_str.len());
|
||||
assert_eq!("💖", result_str);
|
||||
sol_log(result_str);
|
||||
}
|
||||
|
||||
{
|
||||
// Test - struct return
|
||||
|
||||
let s = return_sstruct();
|
||||
sol_log_64(0, 0, s.x, s.y, s.z);
|
||||
assert_eq!(s.x + s.y + s.z, 6);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/target/
|
||||
|
||||
Cargo.lock
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
[package]
|
||||
name = "solana-sdk-bpf-utils"
|
||||
version = "0.15.0"
|
||||
description = "Solana BPF SDK Rust Utils"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
edition = "2018"
|
||||
|
||||
[workspace]
|
||||
members = []
|
|
@ -1,142 +1,21 @@
|
|||
//! @brief Solana Rust-based BPF program utility functions and types
|
||||
|
||||
// extern crate heapless;
|
||||
#![no_std]
|
||||
|
||||
// use self::heapless::consts::*;
|
||||
// use self::heapless::String; // fixed capacity `std::Vec` // type level integer used to specify capacity
|
||||
#[cfg(test)]
|
||||
use self::tests::process;
|
||||
use core::mem::size_of;
|
||||
use core::panic::PanicInfo;
|
||||
use core::slice::from_raw_parts;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use process;
|
||||
use core::panic::PanicInfo;
|
||||
use core::slice::{from_raw_parts, from_raw_parts_mut};
|
||||
|
||||
// Panic handling
|
||||
extern "C" {
|
||||
pub fn sol_panic_() -> !;
|
||||
}
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
sol_log("Panic!");
|
||||
// TODO rashes! sol_log(_info.payload().downcast_ref::<&str>().unwrap());
|
||||
if let Some(location) = _info.location() {
|
||||
if !location.file().is_empty() {
|
||||
// TODO location.file() returns empty str, if we get here its been fixed
|
||||
sol_log(location.file());
|
||||
sol_log("location.file() is fixed!!");
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
}
|
||||
}
|
||||
sol_log_64(0, 0, 0, location.line() as u64, location.column() as u64);
|
||||
} else {
|
||||
sol_log("Panic! but could not get location information");
|
||||
}
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn sol_log_(message: *const u8);
|
||||
}
|
||||
/// Helper function that prints a string to stdout
|
||||
#[inline(never)] // stack intensive, block inline so everyone does not incur
|
||||
pub fn sol_log(message: &str) {
|
||||
// TODO This is extremely slow, do something better
|
||||
let mut buf: [u8; 128] = [0; 128];
|
||||
for (i, b) in message.as_bytes().iter().enumerate() {
|
||||
if i >= 126 {
|
||||
break;
|
||||
}
|
||||
buf[i] = *b;
|
||||
}
|
||||
unsafe {
|
||||
sol_log_(buf.as_ptr());
|
||||
}
|
||||
|
||||
// let mut c_string: String<U256> = String::new();
|
||||
// if message.len() < 256 {
|
||||
// if c_string.push_str(message).is_err() {
|
||||
// c_string
|
||||
// .push_str("Attempted to log a malformed string\0")
|
||||
// .is_ok();
|
||||
// }
|
||||
// if c_string.push('\0').is_err() {
|
||||
// c_string.push_str("Failed to log string\0").is_ok();
|
||||
// };
|
||||
// } else {
|
||||
// c_string
|
||||
// .push_str("Attempted to log a string that is too long\0")
|
||||
// .is_ok();
|
||||
// }
|
||||
// unsafe {
|
||||
// sol_log_(message.as_ptr());
|
||||
// }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64);
|
||||
}
|
||||
/// Helper function that prints a 64 bit values represented in hexadecimal
|
||||
/// to stdout
|
||||
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
||||
unsafe {
|
||||
sol_log_64_(arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of a public key
|
||||
///
|
||||
/// @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() {
|
||||
sol_log_64(0, 0, 0, i as u64, u64::from(*k));
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of a slice
|
||||
///
|
||||
/// @param slice The array to print
|
||||
#[allow(dead_code)]
|
||||
pub fn sol_log_slice(slice: &[u8]) {
|
||||
for (i, s) in slice.iter().enumerate() {
|
||||
sol_log_64(0, 0, 0, i as u64, u64::from(*s));
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of the program's input parameters
|
||||
///
|
||||
/// @param ka A pointer to an array of SolKeyedAccount to print
|
||||
/// @param data A pointer to the instruction data to print
|
||||
#[allow(dead_code)]
|
||||
pub fn sol_log_params(ka: &[SolKeyedAccount], data: &[u8]) {
|
||||
sol_log("- Number of KeyedAccounts");
|
||||
sol_log_64(0, 0, 0, 0, ka.len() as u64);
|
||||
for k in ka.iter() {
|
||||
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);
|
||||
}
|
||||
/// 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],
|
||||
pub key: &'a [u8; SIZE_PUBKEY],
|
||||
}
|
||||
|
||||
/// Keyed Account
|
||||
|
@ -144,11 +23,11 @@ pub struct SolKeyedAccount<'a> {
|
|||
/// Public key of the account
|
||||
pub key: SolPubkey<'a>,
|
||||
/// Public key of the account
|
||||
pub is_signer: u64,
|
||||
pub is_signer: bool,
|
||||
/// Number of lamports owned by this account
|
||||
pub lamports: u64,
|
||||
/// On-chain data within this account
|
||||
pub data: &'a [u8],
|
||||
pub data: &'a mut [u8],
|
||||
/// Program that owns this account
|
||||
pub owner: SolPubkey<'a>,
|
||||
}
|
||||
|
@ -162,9 +41,126 @@ pub struct SolClusterInfo<'a> {
|
|||
pub program_id: SolPubkey<'a>,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
||||
const NUM_KA: usize = 1; // Number of KeyedAccounts expected
|
||||
/// Declare entrypoint of the program.
|
||||
///
|
||||
/// Deserialize the program input parameters and call
|
||||
/// a user defined entrypoint. Users must call
|
||||
/// this function otherwise an entrypoint for
|
||||
/// their program will not be created.
|
||||
#[macro_export]
|
||||
macro_rules! solana_entrypoint {
|
||||
($process_instruction:ident) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
||||
if let Ok((mut ka, info, data)) = $crate::deserialize(input) {
|
||||
// Call use function
|
||||
$process_instruction(&mut ka, &info, &data)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Checks if a public key is default, default implies not set and is
|
||||
/// represented as all zeros
|
||||
///
|
||||
/// @param key - Public key to check
|
||||
pub fn sol_key_default(key_bytes: &[u8]) -> bool {
|
||||
for (_, k) in key_bytes.iter().enumerate() {
|
||||
if *k != 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Prints a string to stdout
|
||||
#[inline(never)] // stack intensive, prevent inline so everyone does not incur cost
|
||||
pub fn sol_log(message: &str) {
|
||||
// TODO This is extremely slow, do something better
|
||||
let mut buf: [u8; 128] = [0; 128];
|
||||
for (i, b) in message.as_bytes().iter().enumerate() {
|
||||
if i >= 126 {
|
||||
break;
|
||||
}
|
||||
buf[i] = *b;
|
||||
}
|
||||
unsafe {
|
||||
sol_log_(buf.as_ptr());
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
fn sol_log_(message: *const u8);
|
||||
}
|
||||
|
||||
/// Prints 64 bit values represented as hexadecimal to stdout
|
||||
pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) {
|
||||
unsafe {
|
||||
sol_log_64_(arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64);
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of a public key
|
||||
///
|
||||
/// @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() {
|
||||
sol_log_64(0, 0, 0, i as u64, u64::from(*k));
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of a slice
|
||||
///
|
||||
/// @param slice - The array to print
|
||||
#[allow(dead_code)]
|
||||
pub fn sol_log_slice(slice: &[u8]) {
|
||||
for (i, s) in slice.iter().enumerate() {
|
||||
sol_log_64(0, 0, 0, i as u64, u64::from(*s));
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the hexadecimal representation of the program's input parameters
|
||||
///
|
||||
/// @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]) {
|
||||
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("Instruction data");
|
||||
sol_log_slice(data);
|
||||
}
|
||||
|
||||
/// Deserialize the input parameters
|
||||
pub fn deserialize<'a>(
|
||||
input: *mut u8,
|
||||
) -> Result<
|
||||
(
|
||||
[Option<SolKeyedAccount<'a>>; MAX_ACCOUNTS],
|
||||
SolClusterInfo<'a>,
|
||||
&'a [u8],
|
||||
),
|
||||
(),
|
||||
> {
|
||||
let mut offset: usize = 0;
|
||||
|
||||
// Number of KeyedAccounts present
|
||||
|
@ -172,25 +168,41 @@ pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
|||
let num_ka = unsafe {
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let num_ka_ptr: *const u64 = input.add(offset) as *const u64;
|
||||
*num_ka_ptr
|
||||
*num_ka_ptr as usize
|
||||
};
|
||||
offset += 8;
|
||||
|
||||
if num_ka != NUM_KA as u64 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// KeyedAccounts
|
||||
|
||||
if num_ka > MAX_ACCOUNTS {
|
||||
sol_log("Error: Too many accounts");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let mut ka: [Option<SolKeyedAccount>; MAX_ACCOUNTS] =
|
||||
[None, None, None, None, None, None, None, None, None, None];
|
||||
let iter = 0..num_ka; // This weirdness due to #issue $#4271
|
||||
for (i, _) in iter.enumerate() {
|
||||
let is_signer = unsafe {
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let is_signer_ptr: *const u64 = input.add(offset) as *const u64;
|
||||
*is_signer_ptr
|
||||
if *is_signer_ptr == 0 {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
offset += size_of::<u64>();
|
||||
|
||||
let key_slice = unsafe { from_raw_parts(input.add(offset), SIZE_PUBKEY) };
|
||||
let key = SolPubkey { key: &key_slice };
|
||||
// let key_slice = unsafe { from_raw_parts(input.add(offset), SIZE_PUBKEY) };
|
||||
// let key = SolPubkey {
|
||||
// key: key_slice.try_into().unwrap(),
|
||||
// };
|
||||
let key = unsafe {
|
||||
SolPubkey {
|
||||
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
|
||||
}
|
||||
};
|
||||
offset += SIZE_PUBKEY;
|
||||
|
||||
let lamports = unsafe {
|
||||
|
@ -207,20 +219,25 @@ pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
|||
} as usize;
|
||||
offset += size_of::<u64>();
|
||||
|
||||
let data = unsafe { from_raw_parts(input.add(offset), data_length) };
|
||||
let data = unsafe { from_raw_parts_mut(input.add(offset), data_length) };
|
||||
offset += data_length;
|
||||
|
||||
let owner_slice = unsafe { from_raw_parts(input.add(offset), SIZE_PUBKEY) };
|
||||
let owner = SolPubkey { key: &owner_slice };
|
||||
// let owner_slice = unsafe { input.add(offset) as *mut [u8; SIZE_PUBKEY] };
|
||||
let owner = unsafe {
|
||||
SolPubkey {
|
||||
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
|
||||
}
|
||||
};
|
||||
offset += SIZE_PUBKEY;
|
||||
|
||||
let mut ka = [SolKeyedAccount {
|
||||
ka[i] = Some(SolKeyedAccount {
|
||||
key,
|
||||
is_signer,
|
||||
lamports,
|
||||
data,
|
||||
owner,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
// Instruction data
|
||||
|
||||
|
@ -245,9 +262,10 @@ pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
|||
|
||||
// Id
|
||||
|
||||
let program_id_slice = unsafe { from_raw_parts(input.add(offset), SIZE_PUBKEY) };
|
||||
let program_id: SolPubkey = SolPubkey {
|
||||
key: &program_id_slice,
|
||||
let program_id = unsafe {
|
||||
SolPubkey {
|
||||
key: &*(input.add(offset) as *mut [u8; SIZE_PUBKEY]),
|
||||
}
|
||||
};
|
||||
|
||||
let info = SolClusterInfo {
|
||||
|
@ -255,8 +273,34 @@ pub extern "C" fn entrypoint(input: *mut u8) -> bool {
|
|||
program_id,
|
||||
};
|
||||
|
||||
// Call user implementable function
|
||||
process(&mut ka, &data, &info)
|
||||
Ok((ka, info, data))
|
||||
}
|
||||
|
||||
// Panic handling
|
||||
extern "C" {
|
||||
pub fn sol_panic_() -> !;
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
sol_log("Panic!");
|
||||
// TODO crashes! sol_log(_info.payload().downcast_ref::<&str>().unwrap());
|
||||
if let Some(location) = _info.location() {
|
||||
if !location.file().is_empty() {
|
||||
// TODO location.file() returns empty str, if we get here its been fixed
|
||||
sol_log(location.file());
|
||||
sol_log("location.file() is fixed!!");
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
}
|
||||
}
|
||||
sol_log_64(0, 0, 0, location.line() as u64, location.column() as u64);
|
||||
} else {
|
||||
sol_log("Panic! but could not get location information");
|
||||
}
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -267,8 +311,9 @@ mod tests {
|
|||
use self::std::println;
|
||||
use self::std::string::String;
|
||||
use super::*;
|
||||
use core::mem;
|
||||
|
||||
static mut _LOG_SCENARIO: u64 = 0;
|
||||
static mut _LOG_SCENARIO: u64 = 4;
|
||||
fn get_log_scenario() -> u64 {
|
||||
unsafe { _LOG_SCENARIO }
|
||||
}
|
||||
|
@ -285,15 +330,15 @@ mod tests {
|
|||
1 => assert_eq!(string, "This is a test message"),
|
||||
2 => assert_eq!(string, "Attempted to log a string that is too long"),
|
||||
3 => {
|
||||
let s: String = ['a'; 255].iter().collect();
|
||||
let s: String = ['a'; 126].iter().collect();
|
||||
assert_eq!(string, s);
|
||||
}
|
||||
4 => println!("{:?}", string),
|
||||
_ => panic!("Unkown sol_log test"),
|
||||
_ => panic!("Unknown sol_log test"),
|
||||
}
|
||||
}
|
||||
|
||||
static mut _LOG_64_SCENARIO: u64 = 0;
|
||||
static mut _LOG_64_SCENARIO: u64 = 4;
|
||||
fn get_log_64_scenario() -> u64 {
|
||||
unsafe { _LOG_64_SCENARIO }
|
||||
}
|
||||
|
@ -337,7 +382,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_sol_log_long() {
|
||||
set_log_scenario(2);
|
||||
set_log_scenario(3);
|
||||
let s: String = ['a'; 256].iter().collect();
|
||||
sol_log(&s);
|
||||
}
|
||||
|
@ -345,7 +390,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_sol_log_max_length() {
|
||||
set_log_scenario(3);
|
||||
let s: String = ['a'; 255].iter().collect();
|
||||
let s: String = ['a'; 126].iter().collect();
|
||||
sol_log(&s);
|
||||
}
|
||||
|
||||
|
@ -376,33 +421,6 @@ mod tests {
|
|||
sol_log_slice(&array);
|
||||
}
|
||||
|
||||
pub fn process(ka: &mut [SolKeyedAccount], data: &[u8], info: &SolClusterInfo) -> bool {
|
||||
assert_eq!(1, ka.len());
|
||||
assert_eq!(1, ka[0].is_signer);
|
||||
let key = [
|
||||
151, 116, 3, 85, 181, 39, 151, 99, 155, 29, 208, 191, 255, 191, 11, 161, 4, 43, 104,
|
||||
189, 202, 240, 231, 111, 146, 255, 199, 71, 67, 34, 254, 68,
|
||||
];
|
||||
assert_eq!(SIZE_PUBKEY, ka[0].key.key.len());
|
||||
assert_eq!(key, ka[0].key.key);
|
||||
assert_eq!(48, ka[0].lamports);
|
||||
assert_eq!(1, ka[0].data.len());
|
||||
let owner = [0; 32];
|
||||
assert_eq!(SIZE_PUBKEY, ka[0].owner.key.len());
|
||||
assert_eq!(owner, ka[0].owner.key);
|
||||
let d = [1, 0, 0, 0, 0, 0, 0, 0, 1];
|
||||
assert_eq!(9, data.len());
|
||||
assert_eq!(d, data);
|
||||
assert_eq!(1, info.tick_height);
|
||||
let program_id = [
|
||||
190, 103, 191, 69, 193, 202, 38, 193, 95, 62, 131, 135, 105, 13, 142, 240, 155, 120,
|
||||
177, 90, 212, 54, 10, 118, 40, 33, 192, 8, 54, 141, 187, 63,
|
||||
];
|
||||
assert_eq!(program_id, info.program_id.key);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entrypoint() {
|
||||
set_log_scenario(4);
|
||||
|
@ -417,6 +435,42 @@ mod tests {
|
|||
10, 118, 40, 33, 192, 8, 54, 141, 187, 63,
|
||||
];
|
||||
|
||||
entrypoint(&mut input[0] as *mut u8);
|
||||
if let Ok((mut ka, info, data)) = deserialize(&mut input[0] as *mut u8) {
|
||||
let account0 = match mem::replace(&mut ka[0], None) {
|
||||
Some(mut account0) => account0,
|
||||
None => {
|
||||
panic!("Error: account not found");
|
||||
}
|
||||
};
|
||||
|
||||
for k in ka[1..].iter() {
|
||||
if let Some(_) = k {
|
||||
panic!("Too many keyed accounts found");
|
||||
}
|
||||
}
|
||||
assert_eq!(true, account0.is_signer);
|
||||
let key: &[u8; SIZE_PUBKEY] = &[
|
||||
151, 116, 3, 85, 181, 39, 151, 99, 155, 29, 208, 191, 255, 191, 11, 161, 4, 43,
|
||||
104, 189, 202, 240, 231, 111, 146, 255, 199, 71, 67, 34, 254, 68,
|
||||
];
|
||||
assert_eq!(SIZE_PUBKEY, account0.key.key.len());
|
||||
assert_eq!(key, account0.key.key);
|
||||
assert_eq!(48, account0.lamports);
|
||||
assert_eq!(1, account0.data.len());
|
||||
let owner = &[0; SIZE_PUBKEY];
|
||||
assert_eq!(SIZE_PUBKEY, account0.owner.key.len());
|
||||
assert_eq!(owner, account0.owner.key);
|
||||
let d = [1, 0, 0, 0, 0, 0, 0, 0, 1];
|
||||
assert_eq!(9, data.len());
|
||||
assert_eq!(d, data);
|
||||
assert_eq!(1, info.tick_height);
|
||||
let program_id: &[u8; SIZE_PUBKEY] = &[
|
||||
190, 103, 191, 69, 193, 202, 38, 193, 95, 62, 131, 135, 105, 13, 142, 240, 155,
|
||||
120, 177, 90, 212, 54, 10, 118, 40, 33, 192, 8, 54, 141, 187, 63,
|
||||
];
|
||||
assert_eq!(program_id, info.program_id.key);
|
||||
} else {
|
||||
panic!("Failed to deserialize");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue