Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
f4ef1eb
CRUD program: create / update / delete (#1226)
joncinque Mar 5, 2021
67bb963
Remove tokio dev-dependency
mvines Mar 16, 2021
510954d
Bump Solana version to 1.5.15
mvines Mar 16, 2021
15bc36b
Bump Rust version to 1.50.0
mvines Mar 16, 2021
5dd33c3
Bump Solana version to 1.6.1
mvines Mar 18, 2021
f0d25cf
Update to Solana 1.6.2
mvines Mar 30, 2021
0ceea0e
Update SPL to Solana v1.6.6
mvines Apr 23, 2021
a6bf2d1
Bump solana crates to v1.6.7
t-nelson May 5, 2021
3b82b3f
ci: Split out test-bpf into separate workflows for each program (#1893)
joncinque Jun 11, 2021
78893c5
Bump solana version
Jun 14, 2021
a23ba45
Update all solana dependencies to 1.7.3, fix issues (#1958)
joncinque Jun 24, 2021
3e3348c
Bump solana and borsh crates (#2015)
CriesofCarrots Jul 2, 2021
c3ec588
build(deps): bump borsh from 0.9.0 to 0.9.1 (#2117)
dependabot[bot] Jul 20, 2021
38ef696
Bump solana crates (#2139)
CriesofCarrots Jul 23, 2021
44d592b
Upgrade to Solana 1.7.11
mvines Aug 30, 2021
68c1a18
Upgrade to Solana 1.8.0
mvines Oct 12, 2021
efafdc9
Upgrade to Solana v1.8.1
mvines Oct 21, 2021
1cad4de
Update tests to prepare for `BanksClientError` (#2657)
joncinque Dec 23, 2021
e25b59d
Update SDK to 1.9.2, fix warnings (#2674)
joncinque Dec 29, 2021
1f9491b
Bump solana crates to v1.9.5 (#2780)
CriesofCarrots Jan 22, 2022
a43556e
Bump solana to v1.9.9 (#2902)
Feb 23, 2022
055584d
Upgrade crates to 1.10.8 (#3076)
joncinque Apr 11, 2022
666197f
Bump token-2022 (#3113)
Apr 26, 2022
af544e8
Bump solana to v1.10.15 (#3176)
dmakarov May 17, 2022
16d38dc
Use target_os instead of target_arch for Solana conditional compilati…
dmakarov May 17, 2022
564394f
Update Solana crates to 1.10.29 (#3303)
joncinque Jul 1, 2022
d07b44d
Bump solana crates to v1.10.33 (#3385)
Jul 27, 2022
97cbeec
Bump solana to v1.10.35 (#3485)
Aug 16, 2022
ae7db7d
Update rust to 1.60, solana to 1.11.6 (#3492)
2501babe Aug 18, 2022
0b778a8
clippy: Deny integer arithmetic, add allows where needed (#3606)
joncinque Sep 15, 2022
286690f
update solana to 1.14.4
2501babe Oct 11, 2022
57ad5b5
upgrade solana-program to 1.14.6 (#3765)
samkim-crypto Oct 26, 2022
e80b044
update solana to 1.14.10 (#3872)
samkim-crypto Dec 6, 2022
2ef2067
Update repo to `edition = "2021"` (#3900)
joncinque Dec 13, 2022
11381bb
ci: Update repo to Solana 1.14.12 (#3989)
joncinque Jan 19, 2023
43ad1f6
chore: update maintainer references (#4008)
softalchemy Jan 31, 2023
c114ace
docs: Clarify audit status of all programs, no S word (#4046)
joncinque Feb 13, 2023
80e4476
borsh: Use `to_writer` API to serialize (#4228)
joncinque May 9, 2023
2c123b3
Update Solana to 1.16.1 and Rust to 1.69 (#4592)
joncinque Jun 26, 2023
31570ac
build(deps): bump num-derive from 0.3.3 to 0.4.0 (#4659)
dependabot[bot] Jun 30, 2023
0e9dc6a
Upgrade to solana 1.16.3 (#4679)
samkim-crypto Jul 13, 2023
471f234
Bump repo to 1.16.13 (#5324)
joncinque Sep 21, 2023
d2c9890
chore: Bump Solana crates to 1.16.16 (#5494)
joncinque Oct 11, 2023
3fcc4d3
ci: Bump repo to Solana 1.17 (#5575)
joncinque Oct 19, 2023
38a75de
rustfmt: use entrypoint full path
Nov 8, 2023
d282b0c
rustfmt: format imports
Nov 8, 2023
795a624
rustfmt: format comments
Nov 8, 2023
0338f41
repo: Update to 1.17.6 (#5863)
joncinque Nov 29, 2023
cdeed31
[spl-record] Remove borsh dependency from spl-record program (#6054)
samkim-crypto Jan 4, 2024
e000df9
[spl-record] Remove `Data` type from `RecordData` type (#6062)
samkim-crypto Jan 5, 2024
57947b4
[spl-record] Add `Reallocate` instruction (#6063)
samkim-crypto Jan 6, 2024
732bb2a
[spl-record] bump to 0.2.0 (#6087)
samkim-crypto Jan 9, 2024
a083c70
[spl-record] add a new program address (#6130)
samkim-crypto Jan 15, 2024
242c1fc
token 2022: upgrade sdk to 1.17.13 (#6147)
0x0ece Jan 18, 2024
13649f3
build(deps): bump bytemuck from 1.14.0 to 1.14.1 (#6179)
dependabot[bot] Jan 25, 2024
5c7d039
Update solana dependency version to allow 2.0.0 (#6182)
willhickey Jan 26, 2024
5bce41d
Upgrade to solana 1.17.17 (#6189)
samkim-crypto Feb 1, 2024
f4d4198
build(deps): bump bytemuck from 1.14.1 to 1.14.2 (#6231)
dependabot[bot] Feb 7, 2024
c5a97bf
build(deps): bump bytemuck from 1.14.2 to 1.14.3 (#6240)
dependabot[bot] Feb 10, 2024
3df7c65
Upgrade to Solana 1.18.2 (#6278)
samkim-crypto Feb 29, 2024
70cf096
build(deps): bump bytemuck from 1.14.3 to 1.15.0 (#6415)
dependabot[bot] Mar 13, 2024
3b29460
pod: Bump to 0.2.0
joncinque Mar 28, 2024
0398c5c
Bump all crates for token-cli release (#6516)
joncinque Mar 28, 2024
6165164
Bump solana version to 1.18.11 (#6624)
samkim-crypto Apr 24, 2024
21b87d3
build(deps): bump bytemuck from 1.15.0 to 1.16.0 (#6729)
dependabot[bot] May 14, 2024
10374fd
build(deps): bump bytemuck from 1.16.0 to 1.16.1 (#6875)
dependabot[bot] Jun 20, 2024
704f5c0
deps: Upgrade to Solana v2 (#6908)
joncinque Jun 25, 2024
31f1027
pod: Bump to 0.3.0 for Solana v2 compat (#6917)
joncinque Jun 25, 2024
51e7f10
ci: Bump crates to Solana 2.0.3 (#7047)
joncinque Jul 25, 2024
a62e29c
build(deps): bump bytemuck from 1.16.1 to 1.16.3 (#7077)
dependabot[bot] Jul 31, 2024
e5371ff
build(deps): bump bytemuck from 1.16.3 to 1.17.0 (#7159)
dependabot[bot] Aug 16, 2024
ee19400
Publish pod v0.3.2
github-actions[bot] Aug 27, 2024
b96b0f1
build(deps): bump bytemuck from 1.17.0 to 1.17.1 (#7209)
dependabot[bot] Aug 28, 2024
56e1a18
Publish pod v0.4.0
github-actions[bot] Aug 28, 2024
475d0b1
Publish record v0.2.1
github-actions[bot] Aug 28, 2024
8ed2439
build(deps): bump bytemuck from 1.17.1 to 1.18.0 (#7244)
dependabot[bot] Sep 6, 2024
70e684f
build(deps): bump bytemuck from 1.18.0 to 1.19.0 (#7345)
dependabot[bot] Oct 14, 2024
b9be66e
CI: Update to Solana v2.1 crates (#7416)
joncinque Oct 31, 2024
7d9a691
Publish spl-pod v0.5.0
github-actions[bot] Nov 1, 2024
adf091c
record: Remove dependency on solana-program (#7445)
joncinque Nov 4, 2024
f3c1387
Publish spl-record v0.3.0
github-actions[bot] Nov 4, 2024
2eb5872
build(deps): bump thiserror from 1.0.68 to 2.0.0 (#7462)
dependabot[bot] Nov 6, 2024
c6e4cec
build(deps): bump bytemuck from 1.19.0 to 1.20.0 (#7507)
dependabot[bot] Nov 20, 2024
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
40 changes: 40 additions & 0 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[package]
name = "spl-record"
version = "0.3.0"
description = "Solana Program Library Record Program"
authors = ["Solana Labs Maintainers <[email protected]>"]
repository = "https://github.com/solana-labs/solana-program-library"
license = "Apache-2.0"
edition = "2021"

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

[dependencies]
bytemuck = { version = "1.20.0", features = ["derive"] }
num-derive = "0.4"
num-traits = "0.2"
solana-account-info = "2.1.0"
solana-decode-error = "2.1.0"
solana-instruction = { version = "2.1.0", features = ["std"] }
solana-msg = "2.1.0"
solana-program-entrypoint = "2.1.0"
solana-program-error = "2.1.0"
solana-program-pack = "2.1.0"
solana-pubkey = { version = "2.1.0", features = ["bytemuck"] }
solana-rent = "2.1.0"
thiserror = "2.0"

[dev-dependencies]
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
9 changes: 9 additions & 0 deletions program/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Record

On-chain program for writing arbitrary data to an account, authorized by an
owner of the account.

## Audit

The repository [README](https://github.com/solana-labs/solana-program-library#audits)
contains information about program audits.
16 changes: 16 additions & 0 deletions program/src/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Program entrypoint

#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))]

use {
solana_account_info::AccountInfo, solana_program_error::ProgramResult, solana_pubkey::Pubkey,
};

solana_program_entrypoint::entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
crate::processor::process_instruction(program_id, accounts, instruction_data)
}
28 changes: 28 additions & 0 deletions program/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! Error types

use {
num_derive::FromPrimitive, solana_decode_error::DecodeError,
solana_program_error::ProgramError, thiserror::Error,
};

/// Errors that may be returned by the program.
#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)]
pub enum RecordError {
/// Incorrect authority provided on update or delete
#[error("Incorrect authority provided on update or delete")]
IncorrectAuthority,

/// Calculation overflow
#[error("Calculation overflow")]
Overflow,
}
impl From<RecordError> for ProgramError {
fn from(e: RecordError) -> Self {
ProgramError::Custom(e as u32)
}
}
impl<T> DecodeError<T> for RecordError {
fn type_of() -> &'static str {
"Record Error"
}
}
260 changes: 260 additions & 0 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
//! Program instructions

use {
crate::id,
solana_instruction::{AccountMeta, Instruction},
solana_program_error::ProgramError,
solana_pubkey::Pubkey,
std::mem::size_of,
};

/// Instructions supported by the program
#[derive(Clone, Debug, PartialEq)]
pub enum RecordInstruction<'a> {
/// Create a new record
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Record account, must be uninitialized
/// 1. `[]` Record authority
Initialize,

/// Write to the provided record account
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Record account, must be previously initialized
/// 1. `[signer]` Current record authority
Write {
/// Offset to start writing record, expressed as `u64`.
offset: u64,
/// Data to replace the existing record data
data: &'a [u8],
},

/// Update the authority of the provided record account
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Record account, must be previously initialized
/// 1. `[signer]` Current record authority
/// 2. `[]` New record authority
SetAuthority,

/// Close the provided record account, draining lamports to recipient
/// account
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` Record account, must be previously initialized
/// 1. `[signer]` Record authority
/// 2. `[]` Receiver of account lamports
CloseAccount,

/// Reallocate additional space in a record account
///
/// If the record account already has enough space to hold the specified
/// data length, then the instruction does nothing.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` The record account to reallocate
/// 1. `[signer]` The account's owner
Reallocate {
/// The length of the data to hold in the record account excluding meta
/// data
data_length: u64,
},
}

impl<'a> RecordInstruction<'a> {
/// Unpacks a byte buffer into a [RecordInstruction].
pub fn unpack(input: &'a [u8]) -> Result<Self, ProgramError> {
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

let (&tag, rest) = input
.split_first()
.ok_or(ProgramError::InvalidInstructionData)?;
Ok(match tag {
0 => Self::Initialize,
1 => {
let offset = rest
.get(..U64_BYTES)
.and_then(|slice| slice.try_into().ok())
.map(u64::from_le_bytes)
.ok_or(ProgramError::InvalidInstructionData)?;
let (length, data) = rest[U64_BYTES..].split_at(U32_BYTES);
let length = u32::from_le_bytes(
length
.try_into()
.map_err(|_| ProgramError::InvalidInstructionData)?,
) as usize;

Self::Write {
offset,
data: &data[..length],
}
}
2 => Self::SetAuthority,
3 => Self::CloseAccount,
4 => {
let data_length = rest
.get(..U64_BYTES)
.and_then(|slice| slice.try_into().ok())
.map(u64::from_le_bytes)
.ok_or(ProgramError::InvalidInstructionData)?;

Self::Reallocate { data_length }
}
_ => return Err(ProgramError::InvalidInstructionData),
})
}

/// Packs a [RecordInstruction] into a byte buffer.
pub fn pack(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(size_of::<Self>());
match self {
Self::Initialize => buf.push(0),
Self::Write { offset, data } => {
buf.push(1);
buf.extend_from_slice(&offset.to_le_bytes());
buf.extend_from_slice(&(data.len() as u32).to_le_bytes());
buf.extend_from_slice(data);
}
Self::SetAuthority => buf.push(2),
Self::CloseAccount => buf.push(3),
Self::Reallocate { data_length } => {
buf.push(4);
buf.extend_from_slice(&data_length.to_le_bytes());
}
};
buf
}
}

/// Create a `RecordInstruction::Initialize` instruction
pub fn initialize(record_account: &Pubkey, authority: &Pubkey) -> Instruction {
Instruction {
program_id: id(),
accounts: vec![
AccountMeta::new(*record_account, false),
AccountMeta::new_readonly(*authority, false),
],
data: RecordInstruction::Initialize.pack(),
}
}

/// Create a `RecordInstruction::Write` instruction
pub fn write(record_account: &Pubkey, signer: &Pubkey, offset: u64, data: &[u8]) -> Instruction {
Instruction {
program_id: id(),
accounts: vec![
AccountMeta::new(*record_account, false),
AccountMeta::new_readonly(*signer, true),
],
data: RecordInstruction::Write { offset, data }.pack(),
}
}

/// Create a `RecordInstruction::SetAuthority` instruction
pub fn set_authority(
record_account: &Pubkey,
signer: &Pubkey,
new_authority: &Pubkey,
) -> Instruction {
Instruction {
program_id: id(),
accounts: vec![
AccountMeta::new(*record_account, false),
AccountMeta::new_readonly(*signer, true),
AccountMeta::new_readonly(*new_authority, false),
],
data: RecordInstruction::SetAuthority.pack(),
}
}

/// Create a `RecordInstruction::CloseAccount` instruction
pub fn close_account(record_account: &Pubkey, signer: &Pubkey, receiver: &Pubkey) -> Instruction {
Instruction {
program_id: id(),
accounts: vec![
AccountMeta::new(*record_account, false),
AccountMeta::new_readonly(*signer, true),
AccountMeta::new(*receiver, false),
],
data: RecordInstruction::CloseAccount.pack(),
}
}

/// Create a `RecordInstruction::Reallocate` instruction
pub fn reallocate(record_account: &Pubkey, signer: &Pubkey, data_length: u64) -> Instruction {
Instruction {
program_id: id(),
accounts: vec![
AccountMeta::new(*record_account, false),
AccountMeta::new_readonly(*signer, true),
],
data: RecordInstruction::Reallocate { data_length }.pack(),
}
}

#[cfg(test)]
mod tests {
use {super::*, crate::state::tests::TEST_BYTES, solana_program_error::ProgramError};

#[test]
fn serialize_initialize() {
let instruction = RecordInstruction::Initialize;
let expected = vec![0];
assert_eq!(instruction.pack(), expected);
assert_eq!(RecordInstruction::unpack(&expected).unwrap(), instruction);
}

#[test]
fn serialize_write() {
let data = &TEST_BYTES;
let offset = 0u64;
let instruction = RecordInstruction::Write { offset: 0, data };
let mut expected = vec![1];
expected.extend_from_slice(&offset.to_le_bytes());
expected.extend_from_slice(&(data.len() as u32).to_le_bytes());
expected.extend_from_slice(data);
assert_eq!(instruction.pack(), expected);
assert_eq!(RecordInstruction::unpack(&expected).unwrap(), instruction);
}

#[test]
fn serialize_set_authority() {
let instruction = RecordInstruction::SetAuthority;
let expected = vec![2];
assert_eq!(instruction.pack(), expected);
assert_eq!(RecordInstruction::unpack(&expected).unwrap(), instruction);
}

#[test]
fn serialize_close_account() {
let instruction = RecordInstruction::CloseAccount;
let expected = vec![3];
assert_eq!(instruction.pack(), expected);
assert_eq!(RecordInstruction::unpack(&expected).unwrap(), instruction);
}

#[test]
fn serialize_reallocate() {
let data_length = 16u64;
let instruction = RecordInstruction::Reallocate { data_length };
let mut expected = vec![4];
expected.extend_from_slice(&data_length.to_le_bytes());
assert_eq!(instruction.pack(), expected);
assert_eq!(RecordInstruction::unpack(&expected).unwrap(), instruction);
}

#[test]
fn deserialize_invalid_instruction() {
let mut expected = vec![12];
expected.extend_from_slice(&TEST_BYTES);
let err: ProgramError = RecordInstruction::unpack(&expected).unwrap_err();
assert_eq!(err, ProgramError::InvalidInstructionData);
}
}
17 changes: 17 additions & 0 deletions program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! Record program
#![deny(missing_docs)]

mod entrypoint;
pub mod error;
pub mod instruction;
pub mod processor;
pub mod state;

// Export current SDK types for downstream users building with a different SDK
// version
pub use {
solana_account_info, solana_decode_error, solana_instruction, solana_msg,
solana_program_entrypoint, solana_program_error, solana_program_pack, solana_pubkey,
};

solana_pubkey::declare_id!("recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5");
Loading