spl_name_service/
processor.rs1use {
2 crate::{
3 instruction::NameRegistryInstruction,
4 state::{get_seeds_and_key, write_data, NameRecordHeader},
5 },
6 borsh::BorshDeserialize,
7 solana_program::{
8 account_info::{next_account_info, AccountInfo},
9 entrypoint::ProgramResult,
10 msg,
11 program::{invoke, invoke_signed},
12 program_error::ProgramError,
13 program_pack::Pack,
14 pubkey::Pubkey,
15 rent::Rent,
16 system_instruction,
17 sysvar::Sysvar,
18 },
19 std::cmp::Ordering,
20};
21
22pub struct Processor {}
23
24impl Processor {
25 pub fn process_create(
26 program_id: &Pubkey,
27 accounts: &[AccountInfo],
28 hashed_name: Vec<u8>,
29 lamports: u64,
30 space: u32,
31 ) -> ProgramResult {
32 let accounts_iter = &mut accounts.iter();
33
34 let system_program = next_account_info(accounts_iter)?;
35 let payer_account = next_account_info(accounts_iter)?;
36 let name_account = next_account_info(accounts_iter)?;
37 let name_owner = next_account_info(accounts_iter)?;
38 let name_class = next_account_info(accounts_iter)?;
39 let parent_name_account = next_account_info(accounts_iter)?;
40 let parent_name_owner = next_account_info(accounts_iter).ok();
41
42 let (name_account_key, seeds) = get_seeds_and_key(
43 program_id,
44 hashed_name,
45 Some(name_class.key),
46 Some(parent_name_account.key),
47 );
48
49 if name_account_key != *name_account.key {
51 msg!("The given name account is incorrect.");
52 return Err(ProgramError::InvalidArgument);
53 }
54 if name_account.data.borrow().len() > 0 {
55 let name_record_header =
56 NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?;
57 if name_record_header.owner != Pubkey::default() {
58 msg!("The given name account already exists.");
59 return Err(ProgramError::InvalidArgument);
60 }
61 }
62 if *name_class.key != Pubkey::default() && !name_class.is_signer {
63 msg!("The given name class is not a signer.");
64 return Err(ProgramError::InvalidArgument);
65 }
66 if *parent_name_account.key != Pubkey::default() {
67 if !parent_name_owner.unwrap().is_signer {
68 msg!("The given parent name account owner is not a signer.");
69 return Err(ProgramError::InvalidArgument);
70 } else {
71 let parent_name_record_header =
72 NameRecordHeader::unpack_from_slice(&parent_name_account.data.borrow())?;
73 if &parent_name_record_header.owner != parent_name_owner.unwrap().key {
74 msg!("The given parent name account owner is not correct.");
75 return Err(ProgramError::InvalidArgument);
76 }
77 }
78 }
79 if name_owner.key == &Pubkey::default() {
80 msg!("The owner cannot be `Pubkey::default()`.");
81 return Err(ProgramError::InvalidArgument);
82 }
83
84 if name_account.data.borrow().len() == 0 {
85 invoke(
90 &system_instruction::transfer(payer_account.key, &name_account_key, lamports),
91 &[
92 payer_account.clone(),
93 name_account.clone(),
94 system_program.clone(),
95 ],
96 )?;
97
98 invoke_signed(
99 &system_instruction::allocate(
100 &name_account_key,
101 NameRecordHeader::LEN.saturating_add(space as usize) as u64,
102 ),
103 &[name_account.clone(), system_program.clone()],
104 &[&seeds.chunks(32).collect::<Vec<&[u8]>>()],
105 )?;
106
107 invoke_signed(
108 &system_instruction::assign(name_account.key, program_id),
109 &[name_account.clone(), system_program.clone()],
110 &[&seeds.chunks(32).collect::<Vec<&[u8]>>()],
111 )?;
112 }
113
114 let name_state = NameRecordHeader {
115 parent_name: *parent_name_account.key,
116 owner: *name_owner.key,
117 class: *name_class.key,
118 };
119
120 name_state.pack_into_slice(&mut name_account.data.borrow_mut());
121
122 Ok(())
123 }
124
125 pub fn process_update(accounts: &[AccountInfo], offset: u32, data: Vec<u8>) -> ProgramResult {
126 let accounts_iter = &mut accounts.iter();
127
128 let name_account = next_account_info(accounts_iter)?;
129 let name_update_signer = next_account_info(accounts_iter)?;
130 let parent_name = next_account_info(accounts_iter).ok();
131
132 let name_record_header = NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?;
133
134 let is_parent_owner = if let Some(parent_name) = parent_name {
136 if name_record_header.parent_name != *parent_name.key {
137 msg!("Invalid parent name account");
138 return Err(ProgramError::InvalidArgument);
139 }
140 let parent_name_record_header =
141 NameRecordHeader::unpack_from_slice(&parent_name.data.borrow())?;
142 parent_name_record_header.owner == *name_update_signer.key
143 } else {
144 false
145 };
146 if !name_update_signer.is_signer {
147 msg!("The given name class or owner is not a signer.");
148 return Err(ProgramError::InvalidArgument);
149 }
150 if name_record_header.class != Pubkey::default()
151 && *name_update_signer.key != name_record_header.class
152 {
153 msg!("The given name class account is incorrect.");
154 return Err(ProgramError::InvalidArgument);
155 }
156 if name_record_header.class == Pubkey::default()
157 && *name_update_signer.key != name_record_header.owner
158 && !is_parent_owner
159 {
160 msg!("The given name owner account is incorrect.");
161 return Err(ProgramError::InvalidArgument);
162 }
163
164 write_data(
165 name_account,
166 &data,
167 NameRecordHeader::LEN.saturating_add(offset as usize),
168 );
169
170 Ok(())
171 }
172
173 pub fn process_transfer(accounts: &[AccountInfo], new_owner: Pubkey) -> ProgramResult {
174 let accounts_iter = &mut accounts.iter();
175
176 let name_account = next_account_info(accounts_iter)?;
177 let name_owner = next_account_info(accounts_iter)?;
178 let name_class_opt = next_account_info(accounts_iter).ok();
179 let parent_name = next_account_info(accounts_iter).ok();
180
181 let mut name_record_header =
182 NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?;
183
184 let is_parent_owner = if let Some(parent_name) = parent_name {
186 if name_record_header.parent_name != *parent_name.key {
187 msg!("Invalid parent name account");
188 return Err(ProgramError::InvalidArgument);
189 }
190 let parent_name_record_header =
191 NameRecordHeader::unpack_from_slice(&parent_name.data.borrow())?;
192 parent_name_record_header.owner == *name_owner.key
193 } else {
194 false
195 };
196 if !name_owner.is_signer
197 || (name_record_header.owner != *name_owner.key && !is_parent_owner)
198 {
199 msg!("The given name owner is incorrect or not a signer.");
200 return Err(ProgramError::InvalidArgument);
201 }
202 if name_record_header.class != Pubkey::default()
203 && (name_class_opt.is_none()
204 || name_record_header.class != *name_class_opt.unwrap().key
205 || !name_class_opt.unwrap().is_signer)
206 {
207 msg!("The given name class account is incorrect or not a signer.");
208 return Err(ProgramError::InvalidArgument);
209 }
210
211 name_record_header.owner = new_owner;
212 name_record_header
213 .pack_into_slice(&mut name_account.data.borrow_mut()[..NameRecordHeader::LEN]);
214
215 Ok(())
216 }
217
218 pub fn process_delete(accounts: &[AccountInfo]) -> ProgramResult {
219 let accounts_iter = &mut accounts.iter();
220
221 let name_account = next_account_info(accounts_iter)?;
222 let name_owner = next_account_info(accounts_iter)?;
223 let refund_target = next_account_info(accounts_iter)?;
224
225 let name_record_header = NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?;
226
227 if !name_owner.is_signer || name_record_header.owner != *name_owner.key {
229 msg!("The given name owner is incorrect or not a signer.");
230 return Err(ProgramError::InvalidArgument);
231 }
232
233 write_data(name_account, &vec![0; name_account.data_len()], 0);
235
236 let source_amount: &mut u64 = &mut name_account.lamports.borrow_mut();
238 let dest_amount: &mut u64 = &mut refund_target.lamports.borrow_mut();
239 *dest_amount = dest_amount.saturating_add(*source_amount);
240 *source_amount = 0;
241
242 Ok(())
243 }
244
245 fn process_realloc(accounts: &[AccountInfo], space: u32) -> ProgramResult {
246 let accounts_iter = &mut accounts.iter();
247 let system_program = next_account_info(accounts_iter)?;
248 let payer_account = next_account_info(accounts_iter)?;
249 let name_account = next_account_info(accounts_iter)?;
250 let name_owner = next_account_info(accounts_iter)?;
251
252 let name_record_header = NameRecordHeader::unpack_from_slice(&name_account.data.borrow())?;
253
254 if !name_owner.is_signer || name_record_header.owner != *name_owner.key {
256 msg!("The given name owner is incorrect or not a signer.");
257 return Err(ProgramError::InvalidArgument);
258 }
259
260 let new_space = NameRecordHeader::LEN.saturating_add(space as usize);
261 let required_lamports = Rent::get()?.minimum_balance(new_space);
262 match name_account.lamports().cmp(&required_lamports) {
263 Ordering::Less => {
264 #[allow(clippy::arithmetic_side_effects)]
266 let lamports_to_add = required_lamports - name_account.lamports();
267 invoke(
268 &system_instruction::transfer(
269 payer_account.key,
270 name_account.key,
271 lamports_to_add,
272 ),
273 &[
274 payer_account.clone(),
275 name_account.clone(),
276 system_program.clone(),
277 ],
278 )?;
279 }
280 Ordering::Greater => {
281 #[allow(clippy::arithmetic_side_effects)]
283 let lamports_to_remove = name_account.lamports() - required_lamports;
284 let source_amount: &mut u64 = &mut name_account.lamports.borrow_mut();
285 let dest_amount: &mut u64 = &mut payer_account.lamports.borrow_mut();
286 *source_amount = source_amount.saturating_sub(lamports_to_remove);
287 *dest_amount = dest_amount.saturating_add(lamports_to_remove);
288 }
289 Ordering::Equal => {}
290 }
291 name_account.realloc(new_space, false)?;
293 Ok(())
294 }
295
296 pub fn process_instruction(
297 program_id: &Pubkey,
298 accounts: &[AccountInfo],
299 instruction_data: &[u8],
300 ) -> ProgramResult {
301 msg!("Beginning processing");
302 let instruction = NameRegistryInstruction::try_from_slice(instruction_data)
303 .map_err(|_| ProgramError::InvalidInstructionData)?;
304 msg!("Instruction unpacked");
305
306 match instruction {
307 NameRegistryInstruction::Create {
308 hashed_name,
309 lamports,
310 space,
311 } => {
312 msg!("Instruction: Create");
313 Processor::process_create(program_id, accounts, hashed_name, lamports, space)?;
314 }
315 NameRegistryInstruction::Update { offset, data } => {
316 msg!("Instruction: Update Data");
317 Processor::process_update(accounts, offset, data)?;
318 }
319 NameRegistryInstruction::Transfer { new_owner } => {
320 msg!("Instruction: Transfer Ownership");
321 Processor::process_transfer(accounts, new_owner)?;
322 }
323 NameRegistryInstruction::Delete => {
324 msg!("Instruction: Delete Name");
325 Processor::process_delete(accounts)?;
326 }
327 NameRegistryInstruction::Realloc { space } => {
328 msg!("Instruction: Realloc Name Record");
329 Processor::process_realloc(accounts, space)?;
330 }
331 }
332 Ok(())
333 }
334}