move program tests to integration
This commit is contained in:
parent
485ba093b3
commit
abd13ba4ca
|
@ -139,10 +139,4 @@ members = [
|
||||||
"programs/print",
|
"programs/print",
|
||||||
"programs/move_funds",
|
"programs/move_funds",
|
||||||
]
|
]
|
||||||
default-members = [
|
|
||||||
".",
|
|
||||||
"common",
|
|
||||||
"programs/noop",
|
|
||||||
"programs/print",
|
|
||||||
"programs/move_funds",
|
|
||||||
]
|
|
||||||
|
|
|
@ -98,11 +98,7 @@ impl DynamicProgram {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use bincode::serialize;
|
|
||||||
use solana_program_interface::account::Account;
|
|
||||||
use solana_program_interface::pubkey::Pubkey;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_library_path() {
|
fn test_create_library_path() {
|
||||||
|
@ -114,131 +110,6 @@ mod tests {
|
||||||
assert_eq!(true, Path::new(&path).exists());
|
assert_eq!(true, Path::new(&path).exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_program_noop() {
|
|
||||||
let data: Vec<u8> = vec![0];
|
|
||||||
let keys = vec![Pubkey::default(); 2];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dp = DynamicProgram::new("noop".to_string());
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn test_program_print() {
|
|
||||||
let data: Vec<u8> = vec![0];
|
|
||||||
let keys = vec![Pubkey::default(); 2];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dp = DynamicProgram::new("print".to_string());
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_program_move_funds_success() {
|
|
||||||
let tokens: i64 = 100;
|
|
||||||
let data: Vec<u8> = serialize(&tokens).unwrap();
|
|
||||||
let keys = vec![Pubkey::default(); 2];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dp = DynamicProgram::new("move_funds".to_string());
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
assert_eq!(0, accounts[0].tokens);
|
|
||||||
assert_eq!(101, accounts[1].tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_program_move_funds_insufficient_funds() {
|
|
||||||
let tokens: i64 = 100;
|
|
||||||
let data: Vec<u8> = serialize(&tokens).unwrap();
|
|
||||||
let keys = vec![Pubkey::default(); 2];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 10;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dp = DynamicProgram::new("move_funds".to_string());
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
assert_eq!(10, accounts[0].tokens);
|
|
||||||
assert_eq!(1, accounts[1].tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_program_move_funds_succes_many_threads() {
|
|
||||||
let num_threads = 42; // number of threads to spawn
|
|
||||||
let num_iters = 100; // number of iterations of test in each thread
|
|
||||||
let mut threads = Vec::new();
|
|
||||||
for _t in 0..num_threads {
|
|
||||||
threads.push(thread::spawn(move || {
|
|
||||||
for _i in 0..num_iters {
|
|
||||||
{
|
|
||||||
let tokens: i64 = 100;
|
|
||||||
let data: Vec<u8> = serialize(&tokens).unwrap();
|
|
||||||
let keys = vec![Pubkey::default(); 2];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dp = DynamicProgram::new("move_funds".to_string());
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
assert_eq!(0, accounts[0].tokens);
|
|
||||||
assert_eq!(101, accounts[1].tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for thread in threads {
|
|
||||||
thread.join().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO add more tests to validate the Userdata and Account data is
|
// TODO add more tests to validate the Userdata and Account data is
|
||||||
// moving across the boundary correctly
|
// moving across the boundary correctly
|
||||||
|
|
||||||
|
|
|
@ -97,14 +97,12 @@ impl SystemProgram {
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use bincode::serialize;
|
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use signature::{Keypair, KeypairUtil};
|
use signature::{Keypair, KeypairUtil};
|
||||||
use solana_program_interface::account::{Account, KeyedAccount};
|
use solana_program_interface::account::Account;
|
||||||
use solana_program_interface::pubkey::Pubkey;
|
use solana_program_interface::pubkey::Pubkey;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::thread;
|
|
||||||
use system_program::SystemProgram;
|
use system_program::SystemProgram;
|
||||||
use system_transaction::SystemTransaction;
|
use system_transaction::SystemTransaction;
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
|
@ -216,112 +214,6 @@ mod test {
|
||||||
assert_eq!(accounts[1].userdata.len(), 3);
|
assert_eq!(accounts[1].userdata.len(), 3);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_call() {
|
|
||||||
// first load the program
|
|
||||||
let loaded_programs = RwLock::new(HashMap::new());
|
|
||||||
{
|
|
||||||
let from = Keypair::new();
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
let program_id = Pubkey::default(); // same program id for both
|
|
||||||
let tx = Transaction::system_load(
|
|
||||||
&from,
|
|
||||||
Hash::default(),
|
|
||||||
0,
|
|
||||||
program_id,
|
|
||||||
"move_funds".to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
SystemProgram::process_transaction(&tx, &mut accounts, &loaded_programs);
|
|
||||||
}
|
|
||||||
// then call the program
|
|
||||||
{
|
|
||||||
let program_id = Pubkey::default(); // same program id for both
|
|
||||||
let keys = vec![Pubkey::default(), Pubkey::default()];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
let tokens: i64 = 100;
|
|
||||||
let data: Vec<u8> = serialize(&tokens).unwrap();
|
|
||||||
{
|
|
||||||
let hash = loaded_programs.write().unwrap();
|
|
||||||
match hash.get(&program_id) {
|
|
||||||
Some(dp) => {
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
None => panic!("failed to find program in hash"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(0, accounts[0].tokens);
|
|
||||||
assert_eq!(101, accounts[1].tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_load_call_many_threads() {
|
|
||||||
let num_threads = 42;
|
|
||||||
let num_iters = 100;
|
|
||||||
let mut threads = Vec::new();
|
|
||||||
for _t in 0..num_threads {
|
|
||||||
threads.push(thread::spawn(move || {
|
|
||||||
let _tid = thread::current().id();
|
|
||||||
for _i in 0..num_iters {
|
|
||||||
// first load the program
|
|
||||||
let loaded_programs = RwLock::new(HashMap::new());
|
|
||||||
{
|
|
||||||
let from = Keypair::new();
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
let program_id = Pubkey::default(); // same program id for both
|
|
||||||
let tx = Transaction::system_load(
|
|
||||||
&from,
|
|
||||||
Hash::default(),
|
|
||||||
0,
|
|
||||||
program_id,
|
|
||||||
"move_funds".to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
SystemProgram::process_transaction(&tx, &mut accounts, &loaded_programs);
|
|
||||||
}
|
|
||||||
// then call the program
|
|
||||||
{
|
|
||||||
let program_id = Pubkey::default(); // same program id for both
|
|
||||||
let keys = vec![Pubkey::default(), Pubkey::default()];
|
|
||||||
let mut accounts = vec![Account::default(), Account::default()];
|
|
||||||
accounts[0].tokens = 100;
|
|
||||||
accounts[1].tokens = 1;
|
|
||||||
let tokens: i64 = 100;
|
|
||||||
let data: Vec<u8> = serialize(&tokens).unwrap();
|
|
||||||
{
|
|
||||||
let hash = loaded_programs.write().unwrap();
|
|
||||||
match hash.get(&program_id) {
|
|
||||||
Some(dp) => {
|
|
||||||
let mut infos: Vec<_> = (&keys)
|
|
||||||
.into_iter()
|
|
||||||
.zip(&mut accounts)
|
|
||||||
.map(|(key, account)| KeyedAccount { key, account })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
dp.call(&mut infos, &data);
|
|
||||||
}
|
|
||||||
None => panic!("failed to find program in hash"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(0, accounts[0].tokens);
|
|
||||||
assert_eq!(101, accounts[1].tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for thread in threads {
|
|
||||||
thread.join().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_create_assign() {
|
fn test_create_assign() {
|
||||||
let from = Keypair::new();
|
let from = Keypair::new();
|
||||||
let program = Keypair::new();
|
let program = Keypair::new();
|
||||||
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
extern crate bincode;
|
||||||
|
extern crate solana;
|
||||||
|
extern crate solana_program_interface;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use bincode::serialize;
|
||||||
|
|
||||||
|
use solana::dynamic_program::DynamicProgram;
|
||||||
|
use solana::hash::Hash;
|
||||||
|
use solana::signature::{Keypair, KeypairUtil};
|
||||||
|
use solana::system_program::SystemProgram;
|
||||||
|
use solana::system_transaction::SystemTransaction;
|
||||||
|
use solana::transaction::Transaction;
|
||||||
|
use solana_program_interface::account::{Account, KeyedAccount};
|
||||||
|
use solana_program_interface::pubkey::Pubkey;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_native_noop() {
|
||||||
|
let data: Vec<u8> = vec![0];
|
||||||
|
let keys = vec![Pubkey::default(); 2];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dp = DynamicProgram::new("noop".to_string());
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_native_print() {
|
||||||
|
let data: Vec<u8> = vec![0];
|
||||||
|
let keys = vec![Pubkey::default(); 2];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dp = DynamicProgram::new("print".to_string());
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_native_move_funds_success() {
|
||||||
|
let tokens: i64 = 100;
|
||||||
|
let data: Vec<u8> = serialize(&tokens).unwrap();
|
||||||
|
let keys = vec![Pubkey::default(); 2];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dp = DynamicProgram::new("move_funds".to_string());
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
assert_eq!(0, accounts[0].tokens);
|
||||||
|
assert_eq!(101, accounts[1].tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_native_move_funds_insufficient_funds() {
|
||||||
|
let tokens: i64 = 100;
|
||||||
|
let data: Vec<u8> = serialize(&tokens).unwrap();
|
||||||
|
let keys = vec![Pubkey::default(); 2];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 10;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dp = DynamicProgram::new("move_funds".to_string());
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
assert_eq!(10, accounts[0].tokens);
|
||||||
|
assert_eq!(1, accounts[1].tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_native_move_funds_succes_many_threads() {
|
||||||
|
let num_threads = 42; // number of threads to spawn
|
||||||
|
let num_iters = 100; // number of iterations of test in each thread
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
for _t in 0..num_threads {
|
||||||
|
threads.push(thread::spawn(move || {
|
||||||
|
for _i in 0..num_iters {
|
||||||
|
{
|
||||||
|
let tokens: i64 = 100;
|
||||||
|
let data: Vec<u8> = serialize(&tokens).unwrap();
|
||||||
|
let keys = vec![Pubkey::default(); 2];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let dp = DynamicProgram::new("move_funds".to_string());
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
assert_eq!(0, accounts[0].tokens);
|
||||||
|
assert_eq!(101, accounts[1].tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for thread in threads {
|
||||||
|
thread.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_program_load_call() {
|
||||||
|
// first load the program
|
||||||
|
let loaded_programs = RwLock::new(HashMap::new());
|
||||||
|
{
|
||||||
|
let from = Keypair::new();
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
let program_id = Pubkey::default(); // same program id for both
|
||||||
|
let tx = Transaction::system_load(
|
||||||
|
&from,
|
||||||
|
Hash::default(),
|
||||||
|
0,
|
||||||
|
program_id,
|
||||||
|
"move_funds".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
SystemProgram::process_transaction(&tx, &mut accounts, &loaded_programs);
|
||||||
|
}
|
||||||
|
// then call the program
|
||||||
|
{
|
||||||
|
let program_id = Pubkey::default(); // same program id for both
|
||||||
|
let keys = vec![Pubkey::default(), Pubkey::default()];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
let tokens: i64 = 100;
|
||||||
|
let data: Vec<u8> = serialize(&tokens).unwrap();
|
||||||
|
{
|
||||||
|
let hash = loaded_programs.write().unwrap();
|
||||||
|
match hash.get(&program_id) {
|
||||||
|
Some(dp) => {
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
None => panic!("failed to find program in hash"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(0, accounts[0].tokens);
|
||||||
|
assert_eq!(101, accounts[1].tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_system_program_load_call_many_threads() {
|
||||||
|
let num_threads = 42;
|
||||||
|
let num_iters = 100;
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
for _t in 0..num_threads {
|
||||||
|
threads.push(thread::spawn(move || {
|
||||||
|
let _tid = thread::current().id();
|
||||||
|
for _i in 0..num_iters {
|
||||||
|
// first load the program
|
||||||
|
let loaded_programs = RwLock::new(HashMap::new());
|
||||||
|
{
|
||||||
|
let from = Keypair::new();
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
let program_id = Pubkey::default(); // same program id for both
|
||||||
|
let tx = Transaction::system_load(
|
||||||
|
&from,
|
||||||
|
Hash::default(),
|
||||||
|
0,
|
||||||
|
program_id,
|
||||||
|
"move_funds".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
SystemProgram::process_transaction(&tx, &mut accounts, &loaded_programs);
|
||||||
|
}
|
||||||
|
// then call the program
|
||||||
|
{
|
||||||
|
let program_id = Pubkey::default(); // same program id for both
|
||||||
|
let keys = vec![Pubkey::default(), Pubkey::default()];
|
||||||
|
let mut accounts = vec![Account::default(), Account::default()];
|
||||||
|
accounts[0].tokens = 100;
|
||||||
|
accounts[1].tokens = 1;
|
||||||
|
let tokens: i64 = 100;
|
||||||
|
let data: Vec<u8> = serialize(&tokens).unwrap();
|
||||||
|
{
|
||||||
|
let hash = loaded_programs.write().unwrap();
|
||||||
|
match hash.get(&program_id) {
|
||||||
|
Some(dp) => {
|
||||||
|
let mut infos: Vec<_> = (&keys)
|
||||||
|
.into_iter()
|
||||||
|
.zip(&mut accounts)
|
||||||
|
.map(|(key, account)| KeyedAccount { key, account })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
dp.call(&mut infos, &data);
|
||||||
|
}
|
||||||
|
None => panic!("failed to find program in hash"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(0, accounts[0].tokens);
|
||||||
|
assert_eq!(101, accounts[1].tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for thread in threads {
|
||||||
|
thread.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue