Skip to content

Commit

Permalink
test: Add spl-token program test
Browse files Browse the repository at this point in the history
  • Loading branch information
conr2d committed Jan 2, 2025
1 parent 5824560 commit bb17135
Show file tree
Hide file tree
Showing 20 changed files with 11,052 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ members = [
"vendor/solana/programs/compute-budget",
"vendor/solana/programs/loader-v4",
"vendor/solana/programs/system",
"vendor/solana/programs/token",
]
default-members = [
"core-primitives",
Expand Down Expand Up @@ -182,6 +183,7 @@ solana-metrics = { path = "vendor/solana/metrics" }
solana-poseidon = { path = "vendor/solana/poseidon", default-features = false }
solana-program-runtime = { path = "vendor/solana/program-runtime", default-features = false }
solana-system-program = { path = "vendor/solana/programs/system", default-features = false }
spl-token = { path = "vendor/solana/programs/token" }

[profile.release]
panic = "unwind"
Expand Down
1 change: 1 addition & 0 deletions frame/solana/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ rand = { workspace = true, default-features = true }
solana-sdk = { workspace = true, features = ["dev-context-only-utils"] }
sp-core = { workspace = true, default-features = true }
sp-io = { workspace = true, default-features = true }
spl-token = { workspace = true }

[features]
default = ["std"]
Expand Down
15 changes: 10 additions & 5 deletions frame/solana/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,23 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![
(Keypair::alice().account_id(), 10_000_000_000_000_000_000u128),
(Keypair::bob().account_id(), 10_000_000_000_000_000_000u128),
(Keypair::alice().account_id(), sol_into_balances(10)),
(Keypair::bob().account_id(), sol_into_balances(10)),
],
}
.assimilate_storage(&mut t)
.unwrap();
t.into()
}

pub const fn sol_into_lamports(sol: u64) -> u64 {
sol * 10u64.pow(9)
}

pub const fn sol_into_balances(sol: u64) -> Balance {
(sol_into_lamports(sol) as Balance) * 10u128.pow(9)
}

pub trait KeypairExt: Sized {
fn create() -> Self;

Expand All @@ -138,9 +146,6 @@ pub trait KeypairExt: Sized {
fn bob() -> Self {
Self::get("Bob")
}
fn charlie() -> Self {
Self::get("Charlie")
}
}

fn pair_to_bytes(pair: Pair) -> [u8; 64] {
Expand Down
141 changes: 123 additions & 18 deletions frame/solana/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,26 @@ use crate::{mock::*, runtime::bank::Bank, *};

use frame_support::{
sp_runtime::traits::Convert,
traits::{fungible::Inspect, Get},
traits::{
fungible::{Inspect, Mutate},
Get,
},
BoundedVec,
};
use frame_system::pallet_prelude::BlockNumberFor;
use solana_sdk::{
bpf_loader_upgradeable,
bpf_loader, bpf_loader_upgradeable,
hash::Hash,
instruction::{self, Instruction},
message::SimpleAddressLoader,
program_pack::Pack,
reserved_account_keys::ReservedAccountKeys,
signature::{Keypair, Signer},
system_program, system_transaction,
system_instruction, system_program, system_transaction,
transaction::{MessageHash, Result, SanitizedTransaction, Transaction, VersionedTransaction},
};

fn before_each() -> Bank<Test> {
fn before_each() {
<AccountMeta<Test>>::insert(
&Keypair::alice().account_id(),
AccountMetadata { rent_epoch: u64::MAX, owner: system_program::id(), executable: false },
Expand All @@ -43,8 +49,8 @@ fn before_each() -> Bank<Test> {
AccountMetadata { rent_epoch: u64::MAX, owner: system_program::id(), executable: false },
);

System::set_block_number(2);
<Slot<Test>>::put(2);
set_block_number(2);

let blockhash = HashConversion::convert(Hash::default());
<BlockhashQueue<Test>>::insert(
blockhash,
Expand All @@ -54,8 +60,15 @@ fn before_each() -> Bank<Test> {
timestamp: <<Test as Config>::GenesisTimestamp as Get<u64>>::get() + 400,
},
);
}

fn set_block_number(n: BlockNumberFor<Test>) {
System::set_block_number(n);
<Slot<Test>>::put(n);
}

<Bank<Test>>::new(<Slot<Test>>::get())
fn mock_bank() -> Bank<Test> {
Bank::new(<Slot<Test>>::get())
}

fn process_transaction(bank: &Bank<Test>, tx: Transaction) -> Result<()> {
Expand All @@ -72,32 +85,45 @@ fn process_transaction(bank: &Bank<Test>, tx: Transaction) -> Result<()> {
bank.load_execute_and_commit_sanitized_transaction(sanitized_tx)
}

fn deploy_program(program_id: &Pubkey, data: Vec<u8>) {
let who = AccountIdConversion::convert(*program_id);
System::inc_providers(&who);
Balances::mint_into(&who, sol_into_balances(1)).unwrap();
<AccountMeta<Test>>::insert(
&who,
AccountMetadata { rent_epoch: u64::MAX, owner: bpf_loader::id(), executable: true },
);
<AccountData<Test>>::insert(&who, BoundedVec::try_from(data).expect("account data"));
}

#[test]
fn create_account_tx_should_work() {
new_test_ext().execute_with(|| {
let bank = before_each();
before_each();
let bank = mock_bank();

let from = Keypair::alice();
let to = Keypair::charlie();
let to = Keypair::get("Account");

let tx = system_transaction::create_account(
&from,
&to,
Hash::default(),
1_000_000_000,
sol_into_lamports(1),
0,
&system_program::id(),
);

assert!(process_transaction(&bank, tx).is_ok());
assert_eq!(Balances::total_balance(&to.account_id()), 1_000_000_000_000_000_000u128);
assert_eq!(Balances::total_balance(&to.account_id()), sol_into_balances(1));
});
}

#[test]
fn deploy_program_tx_should_work() {
new_test_ext().execute_with(|| {
let bank = before_each();
before_each();
let bank = mock_bank();

let payer = Keypair::alice();
let program_keypair = Keypair::get("Program");
Expand All @@ -106,9 +132,9 @@ fn deploy_program_tx_should_work() {
let program_data =
std::fs::read("tests/example-programs/simple-transfer/simple_transfer_program.so")
.expect("program data");
let program_account_balance = 1_000_000_000;
let program_account_balance = sol_into_lamports(1);
let buffer_account_space = program_data.len();
let buffer_account_balance = 1_000_000_000;
let buffer_account_balance = sol_into_lamports(1);

let create_buffer = bpf_loader_upgradeable::create_buffer(
&payer.pubkey(),
Expand Down Expand Up @@ -151,10 +177,13 @@ fn deploy_program_tx_should_work() {
tx.sign(&[&payer, &program_keypair], Hash::default());
assert!(process_transaction(&bank, tx).is_ok());

set_block_number(3);
let bank = mock_bank();

let recipient = Keypair::bob();
let simple_transfer = Instruction::new_with_bytes(
program_keypair.pubkey(),
&1_000_000_000u64.to_be_bytes(),
&sol_into_lamports(1).to_be_bytes(),
vec![
instruction::AccountMeta::new(payer.pubkey(), true),
instruction::AccountMeta::new(recipient.pubkey(), false),
Expand All @@ -165,9 +194,85 @@ fn deploy_program_tx_should_work() {
tx.sign(&[&payer], Hash::default());

assert!(process_transaction(&bank, tx).is_ok());
assert_eq!(
Balances::total_balance(&recipient.account_id()),
11_000_000_000_000_000_000u128
assert_eq!(Balances::total_balance(&recipient.account_id()), sol_into_balances(11));
});
}

#[test]
fn spl_token_program_should_work() {
new_test_ext().execute_with(|| {
before_each();
let bank = mock_bank();

let authority = Keypair::alice();
let owner = Keypair::bob();
let mint = Keypair::get("Mint");

let token_program_id = Pubkey::parse("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
let program_data =
std::fs::read("tests/example-programs/token/token_program.so").expect("program data");

deploy_program(&token_program_id, program_data);

let create_account = system_instruction::create_account(
&authority.pubkey(),
&mint.pubkey(),
sol_into_lamports(1),
82,
&token_program_id,
);
let initialize_mint = spl_token::instruction::initialize_mint2(
&token_program_id,
&mint.pubkey(),
&authority.pubkey(),
None,
9,
)
.expect("initialize_mint2 instruction");
let mut tx = Transaction::new_with_payer(
&[create_account, initialize_mint],
Some(&authority.pubkey()),
);
tx.sign(&[&authority, &mint], Hash::default());
assert!(process_transaction(&bank, tx).is_ok());

let account = Keypair::get("Account");
let create_account = system_instruction::create_account(
&owner.pubkey(),
&account.pubkey(),
sol_into_lamports(1),
165,
&token_program_id,
);
let initialize_account = spl_token::instruction::initialize_account(
&token_program_id,
&account.pubkey(),
&mint.pubkey(),
&owner.pubkey(),
)
.expect("initialize_account instruction");
let mint_to = spl_token::instruction::mint_to(
&token_program_id,
&mint.pubkey(),
&account.pubkey(),
&authority.pubkey(),
&[],
sol_into_lamports(1_000),
)
.expect("mint_to instruction");
let mut tx = Transaction::new_with_payer(
&[create_account, initialize_account, mint_to],
Some(&owner.pubkey()),
);
tx.sign(&[&authority, &account, &owner], Hash::default());
assert!(process_transaction(&bank, tx).is_ok());

let state = spl_token::state::Account::unpack_from_slice(&<AccountData<Test>>::get(
&account.account_id(),
))
.expect("token acccount state");
assert_eq!(state.mint, mint.pubkey());
assert_eq!(state.owner, owner.pubkey());
assert_eq!(state.amount, sol_into_lamports(1_000));
});
}
Binary file not shown.
38 changes: 38 additions & 0 deletions vendor/solana/programs/token/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "spl-token"
version = "7.0.0"
description = "Solana Program Library Token"
authors = ["Solana Labs Maintainers <[email protected]>"]
repository = "https://github.com/solana-labs/solana-program-library"
license = "Apache-2.0"
edition = "2021"
exclude = ["js/**"]

[features]
no-entrypoint = []
test-sbf = []

[dependencies]
arrayref = "0.3.9"
bytemuck = { workspace = true }
num-derive = { workspace = true }
num-traits = { workspace = true }
num_enum = { workspace = true }
solana-program = { workspace = true }
thiserror = { workspace = true, default-features = true }

#[dev-dependencies]
#lazy_static = "1.5.0"
#proptest = "1.6"
#serial_test = "3.2.0"
#solana-program-test = "2.1.0"
#solana-sdk = "2.1.0"

[lib]
crate-type = ["cdylib", "lib"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[lints]
workspace = true
13 changes: 13 additions & 0 deletions vendor/solana/programs/token/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Token program

A token program on the Solana blockchain, usable for fungible and non-fungible tokens.

This program provides an interface and implementation that third parties can
utilize to create and use their tokens.

Full documentation is available at the [SPL Token docs](https://spl.solana.com/token).

## Audit

The repository [README](https://github.com/solana-labs/solana-program-library#audits)
contains information about program audits.
2 changes: 2 additions & 0 deletions vendor/solana/programs/token/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
Loading

0 comments on commit bb17135

Please sign in to comment.