Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build:
@cargo build-sbf

test:
RUST_LOG=off cargo test-sbf --features unit_test_config

fmt:
cargo +nightly fmt
5 changes: 5 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
unstable_features = true
max_width = 80
edition = "2021"
imports_granularity = "Crate"
group_imports = "StdExternalCrate"
3 changes: 2 additions & 1 deletion src/account_size_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const MB: u32 = 1024 * KB;
// That is because each *_size_budget() function includes this constant, so callers must subtract (N-1) instances
// when combining multiple instructions.
//
pub const DLP_PROGRAM_DATA_SIZE_CLASS: AccountSizeClass = AccountSizeClass::Dynamic(350 * KB);
pub const DLP_PROGRAM_DATA_SIZE_CLASS: AccountSizeClass =
AccountSizeClass::Dynamic(350 * KB);

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AccountSizeClass {
Expand Down
5 changes: 3 additions & 2 deletions src/args/commit_state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bytemuck::{Pod, Zeroable};
use std::mem::size_of;

use borsh::{BorshDeserialize, BorshSerialize};
use bytemuck::{Pod, Zeroable};

use crate::args::{ArgsWithBuffer, Boolean};

Expand Down Expand Up @@ -35,7 +35,8 @@ pub struct CommitFinalizeArgs {
pub reserved_padding: [u8; 3],
}

pub type CommitFinalizeArgsWithBuffer<'a> = ArgsWithBuffer<'a, CommitFinalizeArgs>;
pub type CommitFinalizeArgsWithBuffer<'a> =
ArgsWithBuffer<'a, CommitFinalizeArgs>;

#[derive(Default, Debug, BorshSerialize, BorshDeserialize)]
pub struct CommitStateArgs {
Expand Down
16 changes: 9 additions & 7 deletions src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use pinocchio::Address;
use solana_program::pubkey;
use solana_program::pubkey::Pubkey;
use solana_program::{pubkey, pubkey::Pubkey};

/// The delegation session fees (extracted in percentage from the delegation PDAs rent on closure).
pub const RENT_FEES_PERCENTAGE: u8 = 10;
Expand All @@ -15,7 +14,8 @@ pub const COMMIT_FEE_LAMPORTS: u64 = 100_000;
pub const SESSION_FEE_LAMPORTS: u64 = 300_000;

/// The discriminator for the external undelegate instruction.
pub const EXTERNAL_UNDELEGATE_DISCRIMINATOR: [u8; 8] = [196, 28, 41, 206, 48, 37, 51, 167];
pub const EXTERNAL_UNDELEGATE_DISCRIMINATOR: [u8; 8] =
[196, 28, 41, 206, 48, 37, 51, 167];

/// The program ID of the delegation program.
pub const DELEGATION_PROGRAM_ID: Pubkey = crate::id();
Expand All @@ -32,11 +32,13 @@ pub const DEFAULT_VALIDATOR_IDENTITY: Pubkey =
/// The broadcast identity marks an account as undelegatable.
/// Validators treat it as always delegatable, which is safe since such accounts
/// cannot be committed or delegated
pub const BROADCAST_IDENTITY: Pubkey = pubkey!("Broadcast1111111111111111111111111111111111");
pub const BROADCAST_IDENTITY: Pubkey =
pubkey!("Broadcast1111111111111111111111111111111111");

pub const BPF_LOADER_UPGRADEABLE_ID: Address = Address::new_from_array(
const_crypto::bs58::decode_pubkey("BPFLoaderUpgradeab1e11111111111111111111111"),
);
pub const BPF_LOADER_UPGRADEABLE_ID: Address =
Address::new_from_array(const_crypto::bs58::decode_pubkey(
"BPFLoaderUpgradeab1e11111111111111111111111",
));

pub const DELEGATION_PROGRAM_DATA_ID: Address = Address::new_from_array(
const_crypto::ed25519::derive_program_address(
Expand Down
74 changes: 50 additions & 24 deletions src/diff/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ use std::cmp::{min, Ordering};
use pinocchio::error::ProgramError;
use rkyv::util::AlignedVec;

use crate::error::DlpError;

use super::{
DiffSet, OffsetInData, SizeChanged, SIZE_OF_CHANGED_LEN, SIZE_OF_NUM_OFFSET_PAIRS,
SIZE_OF_SINGLE_OFFSET_PAIR,
DiffSet, OffsetInData, SizeChanged, SIZE_OF_CHANGED_LEN,
SIZE_OF_NUM_OFFSET_PAIRS, SIZE_OF_SINGLE_OFFSET_PAIR,
};

use crate::{require_eq, require_le};
use crate::{error::DlpError, require_eq, require_le};

///
/// Compute diff between original and changed.
Expand Down Expand Up @@ -191,7 +188,10 @@ pub fn compute_diff(original: &[u8], changed: &[u8]) -> AlignedVec {
/// - None means NO change
/// - Some(size_changed) means the data size has changed and size_changed indicates
/// whether it has expanded or shrunk.
pub fn detect_size_change(original: &[u8], diffset: &DiffSet<'_>) -> Option<SizeChanged> {
pub fn detect_size_change(
original: &[u8],
diffset: &DiffSet<'_>,
) -> Option<SizeChanged> {
match diffset.changed_len().cmp(&original.len()) {
Ordering::Less => Some(SizeChanged::Shrunk(diffset.changed_len())),
Ordering::Greater => Some(SizeChanged::Expanded(diffset.changed_len())),
Expand All @@ -203,7 +203,10 @@ pub fn detect_size_change(original: &[u8], diffset: &DiffSet<'_>) -> Option<Size
///
/// Precondition:
/// - original.len() must be equal to the length encoded in the diff.
pub fn apply_diff_in_place(original: &mut [u8], diffset: &DiffSet<'_>) -> Result<(), ProgramError> {
pub fn apply_diff_in_place(
original: &mut [u8],
diffset: &DiffSet<'_>,
) -> Result<(), ProgramError> {
if let Some(_layout) = detect_size_change(original, diffset) {
return Err(ProgramError::InvalidInstructionData);
}
Expand All @@ -212,7 +215,10 @@ pub fn apply_diff_in_place(original: &mut [u8], diffset: &DiffSet<'_>) -> Result

/// This function creates a copy of original, possibly extending or shrinking it,
/// and then applies the diff to it, before returning it.
pub fn apply_diff_copy(original: &[u8], diffset: &DiffSet<'_>) -> Result<Vec<u8>, ProgramError> {
pub fn apply_diff_copy(
original: &[u8],
diffset: &DiffSet<'_>,
) -> Result<Vec<u8>, ProgramError> {
Ok(match detect_size_change(original, diffset) {
Some(SizeChanged::Expanded(new_size)) => {
let mut applied = Vec::with_capacity(new_size);
Expand Down Expand Up @@ -273,7 +279,8 @@ pub fn merge_diff_copy<'a>(
if write_index < start {
require_le!(start, original.len(), DlpError::InvalidDiff);
// copy the unchanged bytes
destination[write_index..start].copy_from_slice(&original[write_index..start]);
destination[write_index..start]
.copy_from_slice(&original[write_index..start]);
}

destination[start..end].copy_from_slice(diff_segment);
Expand Down Expand Up @@ -319,12 +326,14 @@ pub fn merge_diff_copy<'a>(
if destination.len() <= original.len() {
// case: all n bytes come from original
let dest_len = destination.len();
destination[write_index..].copy_from_slice(&original[write_index..dest_len]);
destination[write_index..]
.copy_from_slice(&original[write_index..dest_len]);
dest_len
} else if write_index < original.len() {
// case: some bytes come from original and the rest are "assumed" to be
// zero-initialized (by the caller).
destination[write_index..original.len()].copy_from_slice(&original[write_index..]);
destination[write_index..original.len()]
.copy_from_slice(&original[write_index..]);
original.len()
} else {
// case: all N bytes are "assumed" to be zero-initialized (by the caller).
Expand All @@ -344,7 +353,10 @@ pub fn merge_diff_copy<'a>(
}

// private function that does the actual work.
fn apply_diff_impl(original: &mut [u8], diffset: &DiffSet<'_>) -> Result<(), ProgramError> {
fn apply_diff_impl(
original: &mut [u8],
diffset: &DiffSet<'_>,
) -> Result<(), ProgramError> {
for item in diffset.iter() {
let (diff_segment, offset_range) = item?;
original[offset_range].copy_from_slice(diff_segment);
Expand All @@ -361,7 +373,10 @@ mod tests {
Rng, RngCore, SeedableRng,
};

use crate::{apply_diff_copy, apply_diff_in_place, compute_diff, merge_diff_copy, DiffSet};
use crate::{
apply_diff_copy, apply_diff_in_place, compute_diff, merge_diff_copy,
DiffSet,
};

#[test]
fn test_no_change() {
Expand Down Expand Up @@ -395,8 +410,9 @@ mod tests {
// 2 (u32)
expected_diff.extend_from_slice(&2u32.to_le_bytes());
} else {
expected_diff
.extend_from_slice(&(2u32 + additional_changes.len() as u32).to_le_bytes());
expected_diff.extend_from_slice(
&(2u32 + additional_changes.len() as u32).to_le_bytes(),
);
}

// -- offsets
Expand Down Expand Up @@ -450,13 +466,15 @@ mod tests {
assert_eq!(actual_diff.len(), 4 + 4 + 8 + 8 + (4 + 8));
assert_eq!(actual_diff.as_slice(), expected_diff.as_slice());

let expected_changed = apply_diff_copy(&original, &actual_diffset).unwrap();
let expected_changed =
apply_diff_copy(&original, &actual_diffset).unwrap();

assert_eq!(changed.as_slice(), expected_changed.as_slice());

let expected_changed = {
let mut destination = vec![255; original.len()];
merge_diff_copy(&mut destination, &original, &actual_diffset).unwrap();
merge_diff_copy(&mut destination, &original, &actual_diffset)
.unwrap();
destination
};

Expand Down Expand Up @@ -492,7 +510,8 @@ mod tests {

let expected_changed = {
let mut destination = vec![255; CHANGED_LEN];
merge_diff_copy(&mut destination, &original, &actual_diffset).unwrap();
merge_diff_copy(&mut destination, &original, &actual_diffset)
.unwrap();
destination
};

Expand Down Expand Up @@ -525,14 +544,17 @@ mod tests {
//
// TODO (snawaz): we could optimize compute_diff to not include the zero bytes which are
// part of the expansion.
let expected_diff = get_example_expected_diff(CHANGED_LEN, vec![(100, &[0; 20])]);
let expected_diff =
get_example_expected_diff(CHANGED_LEN, vec![(100, &[0; 20])]);

assert_eq!(actual_diff.len(), 4 + 4 + (8 + 8) + (4 + 8) + (4 + 4 + 20));
assert_eq!(actual_diff.as_slice(), expected_diff.as_slice());

let expected_changed = {
let mut destination = vec![255; CHANGED_LEN];
let unwritten = merge_diff_copy(&mut destination, &original, &actual_diffset).unwrap();
let unwritten =
merge_diff_copy(&mut destination, &original, &actual_diffset)
.unwrap();

// TODO (snawaz): unwritten == &mut [], is because currently the expanded bytes are part of the diff.
// Once compute_diff is optimized further, written must be &mut [0; 20].
Expand Down Expand Up @@ -587,7 +609,8 @@ mod tests {
}
}
// println!("{diff_offset}, {diff_end} => {diff_len}");
slices.push((diff_offset, copy[diff_offset..diff_end].to_vec()));
slices
.push((diff_offset, copy[diff_offset..diff_end].to_vec()));

offset_range = (diff_end + 8)..(diff_end + 8 + slab);
}
Expand All @@ -606,7 +629,9 @@ mod tests {
let mut offset_in_diff = 0u32;
for (offset_in_account, slice) in slices.iter() {
diff.extend_from_slice(&offset_in_diff.to_le_bytes());
diff.extend_from_slice(&(*offset_in_account as u32).to_le_bytes());
diff.extend_from_slice(
&(*offset_in_account as u32).to_le_bytes(),
);
offset_in_diff += slice.len() as u32;
}

Expand Down Expand Up @@ -634,7 +659,8 @@ mod tests {

let expected_changed = {
let mut destination = vec![255; original.len()];
merge_diff_copy(&mut destination, &original, &actual_diffset).unwrap();
merge_diff_copy(&mut destination, &original, &actual_diffset)
.unwrap();
destination
};

Expand Down
17 changes: 11 additions & 6 deletions src/diff/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ impl<'a> DiffSet<'a> {
// - raw_pairs aligned to 4-byte
// - raw_pairs is big enough to hold both changed_len and segments_count
this.offset_pairs = unsafe {
let raw_pairs = buf.add(SIZE_OF_CHANGED_LEN + SIZE_OF_NUM_OFFSET_PAIRS)
let raw_pairs = buf
.add(SIZE_OF_CHANGED_LEN + SIZE_OF_NUM_OFFSET_PAIRS)
as *const OffsetPair;
slice::from_raw_parts(raw_pairs, segments_count)
};
Expand All @@ -103,7 +104,9 @@ impl<'a> DiffSet<'a> {
Ok(this)
}

pub fn try_new_from_borsh_vec(vec_buffer: &'a [u8]) -> Result<Self, ProgramError> {
pub fn try_new_from_borsh_vec(
vec_buffer: &'a [u8],
) -> Result<Self, ProgramError> {
if vec_buffer.len() < 4 {
return Err(ProgramError::InvalidInstructionData);
}
Expand Down Expand Up @@ -164,9 +167,10 @@ impl<'a> DiffSet<'a> {
return Err(DlpError::InvalidDiff.into());
}

let segment = &self.concat_diff[segment_begin as usize..segment_end as usize];
let range =
offset_in_data as usize..(offset_in_data + segment_end - segment_begin) as usize;
let segment =
&self.concat_diff[segment_begin as usize..segment_end as usize];
let range = offset_in_data as usize
..(offset_in_data + segment_end - segment_begin) as usize;

if range.end > self.changed_len() {
return Err(DlpError::InvalidDiff.into());
Expand All @@ -178,7 +182,8 @@ impl<'a> DiffSet<'a> {
/// Iterates diff segments
pub fn iter(
&self,
) -> impl Iterator<Item = Result<(&'a [u8], OffsetInData), ProgramError>> + '_ {
) -> impl Iterator<Item = Result<(&'a [u8], OffsetInData), ProgramError>> + '_
{
(0..self.segments_count).map(|index| {
self.diff_segment_at(index)
.map(|val| val.expect("impossible: index can never be greater than segments_count"))
Expand Down
19 changes: 13 additions & 6 deletions src/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{error::DlpError, fast_process_instruction, slow_process_instruction};

use solana_program::entrypoint;

use crate::{
error::DlpError, fast_process_instruction, slow_process_instruction,
};

entrypoint::custom_heap_default!();
entrypoint::custom_panic_default!();

Expand All @@ -15,8 +17,9 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
core::mem::MaybeUninit::<pinocchio::AccountView>::uninit();
let mut accounts = [UNINIT; { pinocchio::MAX_TX_ACCOUNTS }];

let (program_id, count, data) =
pinocchio::entrypoint::deserialize::<{ pinocchio::MAX_TX_ACCOUNTS }>(input, &mut accounts);
let (program_id, count, data) = pinocchio::entrypoint::deserialize::<
{ pinocchio::MAX_TX_ACCOUNTS },
>(input, &mut accounts);

match fast_process_instruction(
program_id,
Expand All @@ -25,7 +28,10 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
) {
Some(Ok(())) => pinocchio::SUCCESS,
Some(Err(error)) => {
pinocchio_log::log!("fast_process_instruction: {}", error.to_str::<DlpError>());
pinocchio_log::log!(
"fast_process_instruction: {}",
error.to_str::<DlpError>()
);
error.into()
}

Expand All @@ -40,7 +46,8 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
/// function name is slow_entrypoint() as opposed to entrypoint() because this is a fallback
/// entrypoint (a slow one).
pub unsafe fn slow_entrypoint(input: *mut u8) -> u64 {
let (program_id, accounts, instruction_data) = unsafe { entrypoint::deserialize(input) };
let (program_id, accounts, instruction_data) =
unsafe { entrypoint::deserialize(input) };
match slow_process_instruction(program_id, &accounts, instruction_data) {
Ok(()) => entrypoint::SUCCESS,
Err(error) => {
Expand Down
13 changes: 11 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ use strum::IntoStaticStr;
use thiserror::Error;

pub const INVALID_ESCROW_PDA: &str = "invalid escrow pda in CallHandler";
pub const INVALID_ESCROW_OWNER: &str = "escrow can not be delegated in CallHandler";
pub const INVALID_ESCROW_OWNER: &str =
"escrow can not be delegated in CallHandler";

#[derive(
Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive, TryFromPrimitive, IntoStaticStr,
Debug,
Error,
Clone,
Copy,
PartialEq,
Eq,
IntoPrimitive,
TryFromPrimitive,
IntoStaticStr,
)]
#[repr(u32)]
pub enum DlpError {
Expand Down
Loading