|
1 | 1 | use std::{collections::BTreeMap, sync::Arc}; |
2 | 2 |
|
| 3 | +use bincode::serialized_size; |
3 | 4 | use crossbeam_channel::{Receiver, Sender}; |
4 | 5 | use itertools::Itertools; |
5 | 6 | use jsonrpc_core::futures::future::join_all; |
@@ -1512,6 +1513,125 @@ impl SurfnetSvmLocker { |
1512 | 1513 | Ok(result.with_new_value(())) |
1513 | 1514 | } |
1514 | 1515 |
|
| 1516 | + pub async fn set_program_authority( |
| 1517 | + &self, |
| 1518 | + remote_ctx: &Option<(SurfnetRemoteClient, CommitmentConfig)>, |
| 1519 | + program_id: Pubkey, |
| 1520 | + new_authority: Option<Pubkey>, |
| 1521 | + ) -> SurfpoolContextualizedResult<()> { |
| 1522 | + let SvmAccessContext { |
| 1523 | + slot, |
| 1524 | + latest_epoch_info, |
| 1525 | + latest_blockhash, |
| 1526 | + inner: mut get_account_result, |
| 1527 | + } = self.get_account(remote_ctx, &program_id, None).await?; |
| 1528 | + |
| 1529 | + let original_authority = match &mut get_account_result { |
| 1530 | + GetAccountResult::None(pubkey) => { |
| 1531 | + return Err(SurfpoolError::invalid_program_account( |
| 1532 | + pubkey, |
| 1533 | + "Account not found", |
| 1534 | + )) |
| 1535 | + } |
| 1536 | + GetAccountResult::FoundAccount(pubkey, program_account, _) => { |
| 1537 | + let programdata_address = get_program_data_address(pubkey); |
| 1538 | + let mut programdata_account_result = self |
| 1539 | + .get_account(remote_ctx, &programdata_address, None) |
| 1540 | + .await? |
| 1541 | + .inner; |
| 1542 | + match &mut programdata_account_result { |
| 1543 | + GetAccountResult::None(pubkey) => { |
| 1544 | + return Err(SurfpoolError::invalid_program_account( |
| 1545 | + pubkey, |
| 1546 | + "Program data account does not exist", |
| 1547 | + )); |
| 1548 | + } |
| 1549 | + GetAccountResult::FoundAccount(_, programdata_account, _) => { |
| 1550 | + let original_authority = update_programdata_account( |
| 1551 | + &program_id, |
| 1552 | + programdata_account, |
| 1553 | + new_authority, |
| 1554 | + )?; |
| 1555 | + |
| 1556 | + get_account_result = GetAccountResult::FoundProgramAccount( |
| 1557 | + (pubkey.clone(), program_account.clone()), |
| 1558 | + (programdata_address, Some(programdata_account.clone())), |
| 1559 | + ); |
| 1560 | + |
| 1561 | + original_authority |
| 1562 | + } |
| 1563 | + GetAccountResult::FoundProgramAccount(_, _) => { |
| 1564 | + return Err(SurfpoolError::invalid_program_account( |
| 1565 | + pubkey, |
| 1566 | + "Not a program account", |
| 1567 | + )); |
| 1568 | + } |
| 1569 | + } |
| 1570 | + } |
| 1571 | + GetAccountResult::FoundProgramAccount(_, (_, None)) => { |
| 1572 | + return Err(SurfpoolError::invalid_program_account( |
| 1573 | + &program_id, |
| 1574 | + "Program data account does not exist", |
| 1575 | + )) |
| 1576 | + } |
| 1577 | + GetAccountResult::FoundProgramAccount(_, (_, Some(programdata_account))) => { |
| 1578 | + update_programdata_account(&program_id, programdata_account, new_authority)? |
| 1579 | + } |
| 1580 | + }; |
| 1581 | + |
| 1582 | + let simnet_events_tx = self.simnet_events_tx(); |
| 1583 | + match (original_authority, new_authority) { |
| 1584 | + (Some(original), Some(new)) => { |
| 1585 | + if original != new { |
| 1586 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!( |
| 1587 | + "Setting new authority for program {}", |
| 1588 | + program_id |
| 1589 | + ))); |
| 1590 | + let _ = simnet_events_tx |
| 1591 | + .send(SimnetEvent::info(format!("Old Authority: {}", original))); |
| 1592 | + let _ = |
| 1593 | + simnet_events_tx.send(SimnetEvent::info(format!("New Authority: {}", new))); |
| 1594 | + } else { |
| 1595 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!( |
| 1596 | + "No authority change for program {}", |
| 1597 | + program_id |
| 1598 | + ))); |
| 1599 | + } |
| 1600 | + } |
| 1601 | + (Some(original), None) => { |
| 1602 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!( |
| 1603 | + "Removing authority for program {}", |
| 1604 | + program_id |
| 1605 | + ))); |
| 1606 | + let _ = simnet_events_tx |
| 1607 | + .send(SimnetEvent::info(format!("Old Authority: {}", original))); |
| 1608 | + } |
| 1609 | + (None, Some(new)) => { |
| 1610 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!( |
| 1611 | + "Setting new authority for program {}", |
| 1612 | + program_id |
| 1613 | + ))); |
| 1614 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!("Old Authority: None"))); |
| 1615 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!("New Authority: {}", new))); |
| 1616 | + } |
| 1617 | + (None, None) => { |
| 1618 | + let _ = simnet_events_tx.send(SimnetEvent::info(format!( |
| 1619 | + "No authority change for program {}", |
| 1620 | + program_id |
| 1621 | + ))); |
| 1622 | + } |
| 1623 | + }; |
| 1624 | + |
| 1625 | + self.write_account_update(get_account_result); |
| 1626 | + |
| 1627 | + Ok(SvmAccessContext::new( |
| 1628 | + slot, |
| 1629 | + latest_epoch_info, |
| 1630 | + latest_blockhash, |
| 1631 | + (), |
| 1632 | + )) |
| 1633 | + } |
| 1634 | + |
1515 | 1635 | pub async fn get_program_accounts( |
1516 | 1636 | &self, |
1517 | 1637 | remote_ctx: &Option<SurfnetRemoteClient>, |
@@ -1767,3 +1887,51 @@ fn apply_rpc_filters(account_data: &[u8], filters: &[RpcFilterType]) -> Surfpool |
1767 | 1887 | pub fn is_supported_token_program(program_id: &Pubkey) -> bool { |
1768 | 1888 | *program_id == spl_token::ID || *program_id == spl_token_2022::ID |
1769 | 1889 | } |
| 1890 | + |
| 1891 | +fn update_programdata_account( |
| 1892 | + program_id: &Pubkey, |
| 1893 | + programdata_account: &mut Account, |
| 1894 | + new_authority: Option<Pubkey>, |
| 1895 | +) -> SurfpoolResult<Option<Pubkey>> { |
| 1896 | + let upgradeable_loader_state = |
| 1897 | + bincode::deserialize::<UpgradeableLoaderState>(&programdata_account.data).map_err(|e| { |
| 1898 | + SurfpoolError::invalid_program_account( |
| 1899 | + &program_id, |
| 1900 | + format!("Failed to serialize program data: {}", e), |
| 1901 | + ) |
| 1902 | + })?; |
| 1903 | + if let UpgradeableLoaderState::ProgramData { |
| 1904 | + upgrade_authority_address, |
| 1905 | + slot, |
| 1906 | + } = upgradeable_loader_state |
| 1907 | + { |
| 1908 | + let offset = if upgrade_authority_address.is_some() { |
| 1909 | + UpgradeableLoaderState::size_of_programdata_metadata() |
| 1910 | + } else { |
| 1911 | + UpgradeableLoaderState::size_of_programdata_metadata() |
| 1912 | + - serialized_size(&Pubkey::default()).unwrap() as usize |
| 1913 | + }; |
| 1914 | + |
| 1915 | + let mut data = bincode::serialize(&UpgradeableLoaderState::ProgramData { |
| 1916 | + upgrade_authority_address: new_authority, |
| 1917 | + slot, |
| 1918 | + }) |
| 1919 | + .map_err(|e| { |
| 1920 | + SurfpoolError::invalid_program_account( |
| 1921 | + &program_id, |
| 1922 | + format!("Failed to serialize program data: {}", e), |
| 1923 | + ) |
| 1924 | + })?; |
| 1925 | + |
| 1926 | + data.append(&mut programdata_account.data[offset..].to_vec()); |
| 1927 | + |
| 1928 | + programdata_account.data = data; |
| 1929 | + |
| 1930 | + Ok(upgrade_authority_address) |
| 1931 | + } else { |
| 1932 | + return Err(SurfpoolError::invalid_program_account( |
| 1933 | + &program_id, |
| 1934 | + "Invalid program data account", |
| 1935 | + )); |
| 1936 | + } |
| 1937 | +} |
0 commit comments