Skip to content

Commit 084ea46

Browse files
committed
added realloc example with tests
1 parent 45e302a commit 084ea46

File tree

13 files changed

+403
-0
lines changed

13 files changed

+403
-0
lines changed

basics/realloc/steel/Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[workspace]
2+
resolver = "2"
3+
members = ["api", "program"]
4+
5+
[workspace.package]
6+
version = "0.1.0"
7+
edition = "2021"
8+
license = "Apache-2.0"
9+
homepage = ""
10+
documentation = ""
11+
repository = ""
12+
readme = "./README.md"
13+
keywords = ["solana"]
14+
15+
[workspace.dependencies]
16+
realloc-api = { path = "./api", version = "0.1.0" }
17+
bytemuck = "1.14"
18+
num_enum = "0.7"
19+
solana-program = "1.18"
20+
steel = "2.0"
21+
thiserror = "1.0"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "realloc-api"
3+
description = "API for interacting with the Realloc program"
4+
version.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
documentation.workspace = true
9+
repository.workspace = true
10+
readme.workspace = true
11+
keywords.workspace = true
12+
13+
[dependencies]
14+
bytemuck.workspace = true
15+
num_enum.workspace = true
16+
solana-program.workspace = true
17+
steel.workspace = true
18+
thiserror.workspace = true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use steel::*;
2+
3+
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive)]
4+
#[repr(u32)]
5+
pub enum ReallocError {
6+
#[error("Invalid string length")]
7+
InvalidStringLength = 0,
8+
}
9+
10+
error!(ReallocError);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use steel::*;
2+
3+
#[repr(u8)]
4+
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
5+
pub enum ReallocInstruction {
6+
Initialize = 0,
7+
Update = 1,
8+
}
9+
10+
#[repr(C)]
11+
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
12+
pub struct Initialize {
13+
pub message: [u8; 1024],
14+
pub len: [u8; 4], // Store as bytes like in escrow
15+
}
16+
17+
#[repr(C)]
18+
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
19+
pub struct Update {
20+
pub message: [u8; 1024],
21+
pub len: [u8; 4],
22+
}
23+
24+
instruction!(ReallocInstruction, Initialize);
25+
instruction!(ReallocInstruction, Update);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
pub mod error;
2+
pub mod instruction;
3+
pub mod state;
4+
pub mod sdk;
5+
6+
pub mod prelude {
7+
pub use crate::error::*;
8+
pub use crate::instruction::*;
9+
pub use crate::state::*;
10+
pub use crate::sdk::*;
11+
pub use solana_program::{
12+
account_info::AccountInfo,
13+
entrypoint::ProgramResult,
14+
msg,
15+
pubkey::Pubkey,
16+
rent::Rent,
17+
system_program,
18+
};
19+
}
20+
21+
use steel::*;
22+
23+
// TODO Set program id
24+
declare_id!("z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35");
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use steel::*;
2+
use crate::prelude::*;
3+
4+
pub fn initialize(
5+
payer: Pubkey,
6+
message_account: Pubkey,
7+
message: String,
8+
) -> Instruction {
9+
let mut message_bytes = [0u8; 1024];
10+
message_bytes[..message.len()].copy_from_slice(message.as_bytes());
11+
12+
Instruction {
13+
program_id: crate::ID,
14+
accounts: vec![
15+
AccountMeta::new(payer, true),
16+
AccountMeta::new(message_account, true),
17+
AccountMeta::new_readonly(system_program::ID, false),
18+
],
19+
data: Initialize {
20+
message: message_bytes,
21+
len: (message.len() as u32).to_le_bytes(),
22+
}.to_bytes(),
23+
}
24+
}
25+
26+
pub fn update(
27+
payer: Pubkey,
28+
message_account: Pubkey,
29+
message: String,
30+
) -> Instruction {
31+
let mut message_bytes = [0u8; 1024];
32+
message_bytes[..message.len()].copy_from_slice(message.as_bytes());
33+
34+
Instruction {
35+
program_id: crate::ID,
36+
accounts: vec![
37+
AccountMeta::new(payer, true),
38+
AccountMeta::new(message_account, false),
39+
AccountMeta::new_readonly(system_program::ID, false),
40+
],
41+
data: Update {
42+
message: message_bytes,
43+
len: (message.len() as u32).to_le_bytes(),
44+
}.to_bytes(),
45+
}
46+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use steel::*;
2+
use super::ReallocAccount;
3+
4+
#[repr(C)]
5+
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
6+
pub struct Message {
7+
pub message: [u8; 1024], // Max message size
8+
pub len: u32, // Actual length of message
9+
}
10+
11+
impl Message {
12+
pub fn required_space(message_len: usize) -> usize {
13+
std::mem::size_of::<Message>()
14+
}
15+
}
16+
17+
account!(ReallocAccount, Message);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use steel::*;
2+
mod message;
3+
4+
#[repr(u8)]
5+
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
6+
pub enum ReallocAccount {
7+
Message = 0,
8+
}
9+
10+
pub use message::*;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "realloc-program"
3+
description = ""
4+
version.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
documentation.workspace = true
9+
repository.workspace = true
10+
readme.workspace = true
11+
keywords.workspace = true
12+
13+
[lib]
14+
crate-type = ["cdylib", "lib"]
15+
16+
[dependencies]
17+
realloc-api.workspace = true
18+
solana-program.workspace = true
19+
steel.workspace = true
20+
21+
[dev-dependencies]
22+
base64 = "0.21"
23+
rand = "0.8.5"
24+
solana-program-test = "1.18"
25+
solana-sdk = "1.18"
26+
tokio = { version = "1.35", features = ["full"] }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use realloc_api::prelude::*;
2+
use steel::*;
3+
4+
pub fn process_initialize(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
5+
let args = Initialize::try_from_bytes(data)?;
6+
let len = u32::from_le_bytes(args.len);
7+
8+
let [payer_info, message_account_info, system_program] = accounts else {
9+
return Err(ProgramError::NotEnoughAccountKeys);
10+
};
11+
12+
payer_info.is_signer()?;
13+
message_account_info.is_signer()?;
14+
15+
// Create the account
16+
let space = Message::required_space(len as usize);
17+
18+
create_account::<Message>(
19+
message_account_info,
20+
system_program,
21+
payer_info,
22+
&realloc_api::ID,
23+
&[],
24+
)?;
25+
26+
// Initialize the message
27+
let message = message_account_info.as_account_mut::<Message>(&realloc_api::ID)?;
28+
message.message = args.message;
29+
message.len = len;
30+
31+
Ok(())
32+
}

0 commit comments

Comments
 (0)