|
13 | 13 | solana_compute_budget::compute_budget::MAX_INSTRUCTION_STACK_DEPTH,
|
14 | 14 | solana_feature_set::{
|
15 | 15 | bpf_account_data_direct_mapping, disable_new_loader_v3_deployments,
|
16 |
| - enable_bpf_loader_set_authority_checked_ix, remove_accounts_executable_flag_checks, |
| 16 | + enable_bpf_loader_set_authority_checked_ix, enable_loader_v4, |
| 17 | + remove_accounts_executable_flag_checks, |
17 | 18 | },
|
18 | 19 | solana_instruction::{error::InstructionError, AccountMeta},
|
19 | 20 | solana_loader_v3_interface::{
|
|
43 | 44 | verifier::RequisiteVerifier,
|
44 | 45 | vm::{ContextObject, EbpfVm},
|
45 | 46 | },
|
46 |
| - solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, native_loader}, |
| 47 | + solana_sdk_ids::{ |
| 48 | + bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4, native_loader, |
| 49 | + system_program, |
| 50 | + }, |
47 | 51 | solana_system_interface::{instruction as system_instruction, MAX_PERMITTED_DATA_LENGTH},
|
48 | 52 | solana_transaction_context::{IndexOfAccount, InstructionContext, TransactionContext},
|
49 | 53 | solana_type_overrides::sync::{atomic::Ordering, Arc},
|
@@ -393,6 +397,10 @@ declare_builtin_function!(
|
393 | 397 | }
|
394 | 398 | );
|
395 | 399 |
|
| 400 | +mod migration_authority { |
| 401 | + solana_pubkey::declare_id!("3Scf35jMNk2xXBD6areNjgMtXgp5ZspDhms8vdcbzC42"); |
| 402 | +} |
| 403 | + |
396 | 404 | #[cfg_attr(feature = "svm-internal", qualifiers(pub))]
|
397 | 405 | pub(crate) fn process_instruction_inner(
|
398 | 406 | invoke_context: &mut InvokeContext,
|
@@ -1337,7 +1345,174 @@ fn process_loader_upgradeable_instruction(
|
1337 | 1345 | );
|
1338 | 1346 | }
|
1339 | 1347 | UpgradeableLoaderInstruction::Migrate => {
|
1340 |
| - return Err(InstructionError::InvalidInstructionData); |
| 1348 | + if !invoke_context |
| 1349 | + .get_feature_set() |
| 1350 | + .is_active(&enable_loader_v4::id()) |
| 1351 | + { |
| 1352 | + return Err(InstructionError::InvalidInstructionData); |
| 1353 | + } |
| 1354 | + |
| 1355 | + instruction_context.check_number_of_instruction_accounts(3)?; |
| 1356 | + let programdata_address = *transaction_context.get_key_of_account_at_index( |
| 1357 | + instruction_context.get_index_of_instruction_account_in_transaction(0)?, |
| 1358 | + )?; |
| 1359 | + let program_address = *transaction_context.get_key_of_account_at_index( |
| 1360 | + instruction_context.get_index_of_instruction_account_in_transaction(1)?, |
| 1361 | + )?; |
| 1362 | + let provided_authority_address = *transaction_context.get_key_of_account_at_index( |
| 1363 | + instruction_context.get_index_of_instruction_account_in_transaction(2)?, |
| 1364 | + )?; |
| 1365 | + let clock_slot = invoke_context |
| 1366 | + .get_sysvar_cache() |
| 1367 | + .get_clock() |
| 1368 | + .map(|clock| clock.slot)?; |
| 1369 | + |
| 1370 | + // Verify ProgramData account |
| 1371 | + let programdata = |
| 1372 | + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; |
| 1373 | + if !programdata.is_writable() { |
| 1374 | + ic_logger_msg!(log_collector, "ProgramData account not writeable"); |
| 1375 | + return Err(InstructionError::InvalidArgument); |
| 1376 | + } |
| 1377 | + let (program_len, upgrade_authority_address) = |
| 1378 | + if let Ok(UpgradeableLoaderState::ProgramData { |
| 1379 | + slot, |
| 1380 | + upgrade_authority_address, |
| 1381 | + }) = programdata.get_state() |
| 1382 | + { |
| 1383 | + if clock_slot == slot { |
| 1384 | + ic_logger_msg!(log_collector, "Program was deployed in this block already"); |
| 1385 | + return Err(InstructionError::InvalidArgument); |
| 1386 | + } |
| 1387 | + ( |
| 1388 | + programdata |
| 1389 | + .get_data() |
| 1390 | + .len() |
| 1391 | + .saturating_sub(UpgradeableLoaderState::size_of_programdata_metadata()), |
| 1392 | + upgrade_authority_address, |
| 1393 | + ) |
| 1394 | + } else { |
| 1395 | + (0, None) |
| 1396 | + }; |
| 1397 | + let programdata_funds = programdata.get_lamports(); |
| 1398 | + drop(programdata); |
| 1399 | + |
| 1400 | + // Verify authority signature |
| 1401 | + if !migration_authority::check_id(&provided_authority_address) |
| 1402 | + && provided_authority_address |
| 1403 | + != upgrade_authority_address.unwrap_or(program_address) |
| 1404 | + { |
| 1405 | + ic_logger_msg!(log_collector, "Incorrect migration authority provided"); |
| 1406 | + return Err(InstructionError::IncorrectAuthority); |
| 1407 | + } |
| 1408 | + if !instruction_context.is_instruction_account_signer(2)? { |
| 1409 | + ic_logger_msg!(log_collector, "Migration authority did not sign"); |
| 1410 | + return Err(InstructionError::MissingRequiredSignature); |
| 1411 | + } |
| 1412 | + |
| 1413 | + // Verify Program account |
| 1414 | + let mut program = |
| 1415 | + instruction_context.try_borrow_instruction_account(transaction_context, 1)?; |
| 1416 | + if !program.is_writable() { |
| 1417 | + ic_logger_msg!(log_collector, "Program account not writeable"); |
| 1418 | + return Err(InstructionError::InvalidArgument); |
| 1419 | + } |
| 1420 | + if program.get_owner() != program_id { |
| 1421 | + ic_logger_msg!(log_collector, "Program account not owned by loader"); |
| 1422 | + return Err(InstructionError::IncorrectProgramId); |
| 1423 | + } |
| 1424 | + if let UpgradeableLoaderState::Program { |
| 1425 | + programdata_address: stored_programdata_address, |
| 1426 | + } = program.get_state()? |
| 1427 | + { |
| 1428 | + if programdata_address != stored_programdata_address { |
| 1429 | + ic_logger_msg!(log_collector, "Program and ProgramData account mismatch"); |
| 1430 | + return Err(InstructionError::InvalidArgument); |
| 1431 | + } |
| 1432 | + } else { |
| 1433 | + ic_logger_msg!(log_collector, "Invalid Program account"); |
| 1434 | + return Err(InstructionError::InvalidAccountData); |
| 1435 | + } |
| 1436 | + program.set_data_from_slice(&[])?; |
| 1437 | + program.checked_add_lamports(programdata_funds)?; |
| 1438 | + if program_len == 0 { |
| 1439 | + program.set_owner(&system_program::id().to_bytes())?; |
| 1440 | + } else { |
| 1441 | + program.set_owner(&loader_v4::id().to_bytes())?; |
| 1442 | + } |
| 1443 | + drop(program); |
| 1444 | + |
| 1445 | + let mut programdata = |
| 1446 | + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; |
| 1447 | + programdata.set_lamports(0)?; |
| 1448 | + drop(programdata); |
| 1449 | + |
| 1450 | + if program_len > 0 { |
| 1451 | + invoke_context.native_invoke( |
| 1452 | + solana_loader_v4_interface::instruction::set_program_length( |
| 1453 | + &program_address, |
| 1454 | + &provided_authority_address, |
| 1455 | + program_len as u32, |
| 1456 | + &program_address, |
| 1457 | + ) |
| 1458 | + .into(), |
| 1459 | + &[], |
| 1460 | + )?; |
| 1461 | + |
| 1462 | + invoke_context.native_invoke( |
| 1463 | + solana_loader_v4_interface::instruction::copy( |
| 1464 | + &program_address, |
| 1465 | + &provided_authority_address, |
| 1466 | + &programdata_address, |
| 1467 | + 0, |
| 1468 | + 0, |
| 1469 | + program_len as u32, |
| 1470 | + ) |
| 1471 | + .into(), |
| 1472 | + &[], |
| 1473 | + )?; |
| 1474 | + |
| 1475 | + invoke_context.native_invoke( |
| 1476 | + solana_loader_v4_interface::instruction::deploy( |
| 1477 | + &program_address, |
| 1478 | + &provided_authority_address, |
| 1479 | + ) |
| 1480 | + .into(), |
| 1481 | + &[], |
| 1482 | + )?; |
| 1483 | + |
| 1484 | + if upgrade_authority_address.is_none() { |
| 1485 | + invoke_context.native_invoke( |
| 1486 | + solana_loader_v4_interface::instruction::finalize( |
| 1487 | + &program_address, |
| 1488 | + &provided_authority_address, |
| 1489 | + &program_address, |
| 1490 | + ) |
| 1491 | + .into(), |
| 1492 | + &[], |
| 1493 | + )?; |
| 1494 | + } else if migration_authority::check_id(&provided_authority_address) { |
| 1495 | + invoke_context.native_invoke( |
| 1496 | + solana_loader_v4_interface::instruction::transfer_authority( |
| 1497 | + &program_address, |
| 1498 | + &provided_authority_address, |
| 1499 | + &upgrade_authority_address.unwrap(), |
| 1500 | + ) |
| 1501 | + .into(), |
| 1502 | + &[], |
| 1503 | + )?; |
| 1504 | + } |
| 1505 | + } |
| 1506 | + |
| 1507 | + let transaction_context = &invoke_context.transaction_context; |
| 1508 | + let instruction_context = transaction_context.get_current_instruction_context()?; |
| 1509 | + let mut programdata = |
| 1510 | + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; |
| 1511 | + programdata.set_data_from_slice(&[])?; |
| 1512 | + programdata.set_owner(&system_program::id().to_bytes())?; |
| 1513 | + drop(programdata); |
| 1514 | + |
| 1515 | + ic_logger_msg!(log_collector, "Migrated program {:?}", &program_address); |
1341 | 1516 | }
|
1342 | 1517 | }
|
1343 | 1518 |
|
@@ -1672,7 +1847,7 @@ mod tests {
|
1672 | 1847 | },
|
1673 | 1848 | solana_pubkey::Pubkey,
|
1674 | 1849 | solana_rent::Rent,
|
1675 |
| - solana_sdk_ids::{system_program, sysvar}, |
| 1850 | + solana_sdk_ids::sysvar, |
1676 | 1851 | std::{fs::File, io::Read, ops::Range, sync::atomic::AtomicU64},
|
1677 | 1852 | };
|
1678 | 1853 |
|
|
0 commit comments