|
3 | 3 | use { |
4 | 4 | crate::{ |
5 | 5 | check_id, |
| 6 | + error::AddressLookupTableError, |
6 | 7 | instruction::AddressLookupTableInstruction, |
7 | 8 | state::{ |
8 | 9 | AddressLookupTable, ProgramState, LOOKUP_TABLE_MAX_ADDRESSES, LOOKUP_TABLE_META_SIZE, |
@@ -145,6 +146,8 @@ fn process_create_lookup_table( |
145 | 146 | )?; |
146 | 147 | } |
147 | 148 |
|
| 149 | + // [Core BPF]: No need to check `is_executable` or `is_writable` here, |
| 150 | + // since they will be checked by System. |
148 | 151 | invoke_signed( |
149 | 152 | &system_instruction::allocate(lookup_table_info.key, lookup_table_data_len as u64), |
150 | 153 | &[lookup_table_info.clone()], |
@@ -205,6 +208,10 @@ fn process_freeze_lookup_table(program_id: &Pubkey, accounts: &[AccountInfo]) -> |
205 | 208 | lookup_table.meta |
206 | 209 | }; |
207 | 210 |
|
| 211 | + // [Core BPF]: No need to check `is_executable` or `is_writable` here, |
| 212 | + // since only non-frozen lookup tables can be frozen (never a same-data |
| 213 | + // write). |
| 214 | + |
208 | 215 | lookup_table_meta.authority = None; |
209 | 216 | AddressLookupTable::overwrite_meta_data( |
210 | 217 | &mut lookup_table_info.try_borrow_mut_data()?[..], |
@@ -297,6 +304,36 @@ fn process_extend_lookup_table( |
297 | 304 | ) |
298 | 305 | }; |
299 | 306 |
|
| 307 | + // [Core BPF]: |
| 308 | + // When a builtin program attempts to write to an executable or read-only |
| 309 | + // account, it will be immediately rejected by the `TransactionContext`. |
| 310 | + // For more information, see https://github.com/solana-program/config/pull/21. |
| 311 | + // |
| 312 | + // However, in the case of the Address Lookup Table program's |
| 313 | + // `ExtendLookupTable` instruction, since the processor rejects any |
| 314 | + // zero-length "new keys" vectors, and will gladly append the same keys |
| 315 | + // again to the table, the issue here is slightly different than the linked |
| 316 | + // PR. |
| 317 | + // |
| 318 | + // The builtin version of the Address Lookup Table program will throw |
| 319 | + // when it attempts to overwrite the metadata, while the BPF version will |
| 320 | + // continue. In the case where an executable or read-only lookup table |
| 321 | + // account is provided, and some other requirement below is violated |
| 322 | + // (ie. no payer or system program accounts provided, payer is not a |
| 323 | + // signer, payer has insufficent balance, etc.), the BPF version will throw |
| 324 | + // based on one of those violations, rather than throwing immediately when |
| 325 | + // it encounters the executable or read-only lookup table account. |
| 326 | + // |
| 327 | + // As a result, this placement of these mocked out `InstructionError` |
| 328 | + // variants ensures maximum backwards compatibility with the builtin |
| 329 | + // version. |
| 330 | + if lookup_table_info.executable { |
| 331 | + return Err(AddressLookupTableError::ExecutableDataModified.into()); |
| 332 | + } |
| 333 | + if !lookup_table_info.is_writable { |
| 334 | + return Err(AddressLookupTableError::ReadonlyDataModified.into()); |
| 335 | + } |
| 336 | + |
300 | 337 | AddressLookupTable::overwrite_meta_data( |
301 | 338 | &mut lookup_table_info.try_borrow_mut_data()?[..], |
302 | 339 | lookup_table_meta, |
@@ -374,6 +411,11 @@ fn process_deactivate_lookup_table(program_id: &Pubkey, accounts: &[AccountInfo] |
374 | 411 | }; |
375 | 412 |
|
376 | 413 | let clock = <Clock as Sysvar>::get()?; |
| 414 | + |
| 415 | + // [Core BPF]: No need to check `is_executable` or `is_writable` here, |
| 416 | + // since only non-deactivated lookup tables can be deactivated (never a |
| 417 | + // same-data write). |
| 418 | + |
377 | 419 | lookup_table_meta.deactivation_slot = clock.slot; |
378 | 420 |
|
379 | 421 | AddressLookupTable::overwrite_meta_data( |
@@ -444,6 +486,10 @@ fn process_close_lookup_table(program_id: &Pubkey, accounts: &[AccountInfo]) -> |
444 | 486 | }?; |
445 | 487 | } |
446 | 488 |
|
| 489 | + // [Core BPF]: No need to check `is_executable` or `is_writable` here, |
| 490 | + // since only non-closed lookup tables can be deactivated. Deserialization |
| 491 | + // would fail earlier in the processor. |
| 492 | + |
447 | 493 | let new_recipient_lamports = lookup_table_info |
448 | 494 | .lamports() |
449 | 495 | .checked_add(recipient_info.lamports()) |
|
0 commit comments