Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit dfb4495

Browse files
authored
Cleanup after simplify_writable_program_account_check feature activation (#34840)
1 parent 3388507 commit dfb4495

File tree

2 files changed

+7
-353
lines changed

2 files changed

+7
-353
lines changed

runtime/src/accounts/mod.rs

Lines changed: 5 additions & 350 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,7 @@ use {
2828
create_executable_meta, is_builtin, is_executable, Account, AccountSharedData,
2929
ReadableAccount, WritableAccount,
3030
},
31-
account_utils::StateMut,
32-
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
33-
feature_set::{
34-
include_loaded_accounts_data_size_in_fee_calculation,
35-
simplify_writable_program_account_check, FeatureSet,
36-
},
31+
feature_set::{include_loaded_accounts_data_size_in_fee_calculation, FeatureSet},
3732
fee::FeeStructure,
3833
message::SanitizedMessage,
3934
native_loader,
@@ -195,12 +190,9 @@ fn load_transaction_accounts(
195190
account_overrides.and_then(|overrides| overrides.get(key))
196191
{
197192
(account_override.data().len(), account_override.clone(), 0)
198-
} else if let Some(program) = (feature_set
199-
.is_active(&simplify_writable_program_account_check::id())
200-
&& !instruction_account
201-
&& !message.is_writable(i))
202-
.then_some(())
203-
.and_then(|_| loaded_programs.find(key))
193+
} else if let Some(program) = (!instruction_account && !message.is_writable(i))
194+
.then_some(())
195+
.and_then(|_| loaded_programs.find(key))
204196
{
205197
// Optimization to skip loading of accounts which are only used as
206198
// programs in top-level instructions and not passed as instruction accounts.
@@ -275,41 +267,6 @@ fn load_transaction_accounts(
275267
validated_fee_payer = true;
276268
}
277269

278-
if !feature_set.is_active(&simplify_writable_program_account_check::id()) {
279-
if bpf_loader_upgradeable::check_id(account.owner()) {
280-
if message.is_writable(i) && !message.is_upgradeable_loader_present() {
281-
error_counters.invalid_writable_account += 1;
282-
return Err(TransactionError::InvalidWritableAccount);
283-
}
284-
285-
if is_builtin(&account) || is_executable(&account, feature_set) {
286-
// The upgradeable loader requires the derived ProgramData account
287-
if let Ok(UpgradeableLoaderState::Program {
288-
programdata_address,
289-
}) = account.state()
290-
{
291-
if accounts_db
292-
.load_with_fixed_root(ancestors, &programdata_address)
293-
.is_none()
294-
{
295-
error_counters.account_not_found += 1;
296-
return Err(TransactionError::ProgramAccountNotFound);
297-
}
298-
} else {
299-
error_counters.invalid_program_for_execution += 1;
300-
return Err(TransactionError::InvalidProgramForExecution);
301-
}
302-
}
303-
} else {
304-
if (is_builtin(&account) || is_executable(&account, feature_set))
305-
&& message.is_writable(i)
306-
{
307-
error_counters.invalid_writable_account += 1;
308-
return Err(TransactionError::InvalidWritableAccount);
309-
}
310-
}
311-
}
312-
313270
if in_reward_interval
314271
&& message.is_writable(i)
315272
&& solana_stake_program::check_id(account.owner())
@@ -548,6 +505,7 @@ mod tests {
548505
},
549506
solana_sdk::{
550507
account::{AccountSharedData, WritableAccount},
508+
bpf_loader_upgradeable,
551509
compute_budget::ComputeBudgetInstruction,
552510
epoch_schedule::EpochSchedule,
553511
hash::Hash,
@@ -1045,309 +1003,6 @@ mod tests {
10451003
}
10461004
}
10471005

1048-
#[test]
1049-
fn test_load_accounts_executable_with_write_lock() {
1050-
let mut accounts: Vec<TransactionAccount> = Vec::new();
1051-
let mut error_counters = TransactionErrorMetrics::default();
1052-
1053-
let keypair = Keypair::new();
1054-
let key0 = keypair.pubkey();
1055-
let key1 = Pubkey::from([5u8; 32]);
1056-
let key2 = Pubkey::from([6u8; 32]);
1057-
1058-
let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
1059-
account.set_rent_epoch(1);
1060-
accounts.push((key0, account));
1061-
1062-
let mut account = AccountSharedData::new(40, 1, &native_loader::id());
1063-
account.set_executable(true);
1064-
account.set_rent_epoch(1);
1065-
accounts.push((key1, account));
1066-
1067-
let mut account = AccountSharedData::new(40, 1, &native_loader::id());
1068-
account.set_executable(true);
1069-
account.set_rent_epoch(1);
1070-
accounts.push((key2, account));
1071-
1072-
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1073-
let mut message = Message::new_with_compiled_instructions(
1074-
1,
1075-
0,
1076-
1, // only one executable marked as readonly
1077-
vec![key0, key1, key2],
1078-
Hash::default(),
1079-
instructions,
1080-
);
1081-
let tx = Transaction::new(&[&keypair], message.clone(), Hash::default());
1082-
let loaded_accounts = load_accounts_with_excluded_features(
1083-
tx,
1084-
&accounts,
1085-
&mut error_counters,
1086-
Some(&[simplify_writable_program_account_check::id()]),
1087-
);
1088-
1089-
assert_eq!(error_counters.invalid_writable_account, 1);
1090-
assert_eq!(loaded_accounts.len(), 1);
1091-
assert_eq!(
1092-
loaded_accounts[0],
1093-
(Err(TransactionError::InvalidWritableAccount), None)
1094-
);
1095-
1096-
// Mark executables as readonly
1097-
message.account_keys = vec![key0, key1, key2]; // revert key change
1098-
message.header.num_readonly_unsigned_accounts = 2; // mark both executables as readonly
1099-
let tx = Transaction::new(&[&keypair], message, Hash::default());
1100-
let loaded_accounts = load_accounts_with_excluded_features(
1101-
tx,
1102-
&accounts,
1103-
&mut error_counters,
1104-
Some(&[simplify_writable_program_account_check::id()]),
1105-
);
1106-
1107-
assert_eq!(error_counters.invalid_writable_account, 1);
1108-
assert_eq!(loaded_accounts.len(), 1);
1109-
let result = loaded_accounts[0].0.as_ref().unwrap();
1110-
assert_eq!(result.accounts[..2], accounts[..2]);
1111-
assert_eq!(
1112-
result.accounts[result.program_indices[0][0] as usize],
1113-
accounts[2]
1114-
);
1115-
}
1116-
1117-
#[test]
1118-
fn test_load_accounts_upgradeable_with_write_lock() {
1119-
let mut accounts: Vec<TransactionAccount> = Vec::new();
1120-
let mut error_counters = TransactionErrorMetrics::default();
1121-
1122-
let keypair = Keypair::new();
1123-
let key0 = keypair.pubkey();
1124-
let key1 = Pubkey::from([5u8; 32]);
1125-
let key2 = Pubkey::from([6u8; 32]);
1126-
let programdata_key1 = Pubkey::from([7u8; 32]);
1127-
let programdata_key2 = Pubkey::from([8u8; 32]);
1128-
1129-
let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
1130-
account.set_rent_epoch(1);
1131-
accounts.push((key0, account));
1132-
1133-
let program_data = UpgradeableLoaderState::ProgramData {
1134-
slot: 42,
1135-
upgrade_authority_address: None,
1136-
};
1137-
1138-
let program = UpgradeableLoaderState::Program {
1139-
programdata_address: programdata_key1,
1140-
};
1141-
let mut account =
1142-
AccountSharedData::new_data(40, &program, &bpf_loader_upgradeable::id()).unwrap();
1143-
account.set_executable(true);
1144-
account.set_rent_epoch(1);
1145-
accounts.push((key1, account));
1146-
let mut account =
1147-
AccountSharedData::new_data(40, &program_data, &bpf_loader_upgradeable::id()).unwrap();
1148-
account.set_rent_epoch(1);
1149-
accounts.push((programdata_key1, account));
1150-
1151-
let program = UpgradeableLoaderState::Program {
1152-
programdata_address: programdata_key2,
1153-
};
1154-
let mut account =
1155-
AccountSharedData::new_data(40, &program, &bpf_loader_upgradeable::id()).unwrap();
1156-
account.set_executable(true);
1157-
account.set_rent_epoch(1);
1158-
accounts.push((key2, account));
1159-
let mut account =
1160-
AccountSharedData::new_data(40, &program_data, &bpf_loader_upgradeable::id()).unwrap();
1161-
account.set_rent_epoch(1);
1162-
accounts.push((programdata_key2, account));
1163-
1164-
let mut account = AccountSharedData::new(40, 1, &native_loader::id()); // create mock bpf_loader_upgradeable
1165-
account.set_executable(true);
1166-
account.set_rent_epoch(1);
1167-
accounts.push((bpf_loader_upgradeable::id(), account));
1168-
1169-
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1170-
let mut message = Message::new_with_compiled_instructions(
1171-
1,
1172-
0,
1173-
1, // only one executable marked as readonly
1174-
vec![key0, key1, key2],
1175-
Hash::default(),
1176-
instructions,
1177-
);
1178-
let tx = Transaction::new(&[&keypair], message.clone(), Hash::default());
1179-
let loaded_accounts = load_accounts_with_excluded_features(
1180-
tx.clone(),
1181-
&accounts,
1182-
&mut error_counters,
1183-
Some(&[simplify_writable_program_account_check::id()]),
1184-
);
1185-
1186-
assert_eq!(error_counters.invalid_writable_account, 1);
1187-
assert_eq!(loaded_accounts.len(), 1);
1188-
assert_eq!(
1189-
loaded_accounts[0],
1190-
(Err(TransactionError::InvalidWritableAccount), None)
1191-
);
1192-
1193-
// Solution 0: Include feature simplify_writable_program_account_check
1194-
let loaded_accounts =
1195-
load_accounts_with_excluded_features(tx, &accounts, &mut error_counters, None);
1196-
1197-
assert_eq!(error_counters.invalid_writable_account, 1);
1198-
assert_eq!(loaded_accounts.len(), 1);
1199-
1200-
// Solution 1: include bpf_loader_upgradeable account
1201-
message.account_keys = vec![key0, key1, bpf_loader_upgradeable::id()];
1202-
let tx = Transaction::new(&[&keypair], message.clone(), Hash::default());
1203-
let loaded_accounts = load_accounts_with_excluded_features(
1204-
tx,
1205-
&accounts,
1206-
&mut error_counters,
1207-
Some(&[simplify_writable_program_account_check::id()]),
1208-
);
1209-
1210-
assert_eq!(error_counters.invalid_writable_account, 1);
1211-
assert_eq!(loaded_accounts.len(), 1);
1212-
let result = loaded_accounts[0].0.as_ref().unwrap();
1213-
assert_eq!(result.accounts[..2], accounts[..2]);
1214-
assert_eq!(
1215-
result.accounts[result.program_indices[0][0] as usize],
1216-
accounts[5]
1217-
);
1218-
1219-
// Solution 2: mark programdata as readonly
1220-
message.account_keys = vec![key0, key1, key2]; // revert key change
1221-
message.header.num_readonly_unsigned_accounts = 2; // mark both executables as readonly
1222-
let tx = Transaction::new(&[&keypair], message, Hash::default());
1223-
let loaded_accounts = load_accounts_with_excluded_features(
1224-
tx,
1225-
&accounts,
1226-
&mut error_counters,
1227-
Some(&[simplify_writable_program_account_check::id()]),
1228-
);
1229-
1230-
assert_eq!(error_counters.invalid_writable_account, 1);
1231-
assert_eq!(loaded_accounts.len(), 1);
1232-
let result = loaded_accounts[0].0.as_ref().unwrap();
1233-
assert_eq!(result.accounts[..2], accounts[..2]);
1234-
assert_eq!(
1235-
result.accounts[result.program_indices[0][0] as usize],
1236-
accounts[5]
1237-
);
1238-
assert_eq!(
1239-
result.accounts[result.program_indices[0][1] as usize],
1240-
accounts[3]
1241-
);
1242-
}
1243-
1244-
#[test]
1245-
fn test_load_accounts_programdata_with_write_lock() {
1246-
let mut accounts: Vec<TransactionAccount> = Vec::new();
1247-
let mut error_counters = TransactionErrorMetrics::default();
1248-
1249-
let keypair = Keypair::new();
1250-
let key0 = keypair.pubkey();
1251-
let key1 = Pubkey::from([5u8; 32]);
1252-
let key2 = Pubkey::from([6u8; 32]);
1253-
1254-
let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
1255-
account.set_rent_epoch(1);
1256-
accounts.push((key0, account));
1257-
1258-
let program_data = UpgradeableLoaderState::ProgramData {
1259-
slot: 42,
1260-
upgrade_authority_address: None,
1261-
};
1262-
let mut account =
1263-
AccountSharedData::new_data(40, &program_data, &bpf_loader_upgradeable::id()).unwrap();
1264-
account.set_rent_epoch(1);
1265-
accounts.push((key1, account));
1266-
1267-
let mut account = AccountSharedData::new(40, 1, &native_loader::id());
1268-
account.set_executable(true);
1269-
account.set_rent_epoch(1);
1270-
accounts.push((key2, account));
1271-
1272-
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
1273-
let mut message = Message::new_with_compiled_instructions(
1274-
1,
1275-
0,
1276-
1, // only the program marked as readonly
1277-
vec![key0, key1, key2],
1278-
Hash::default(),
1279-
instructions,
1280-
);
1281-
let tx = Transaction::new(&[&keypair], message.clone(), Hash::default());
1282-
let loaded_accounts = load_accounts_with_excluded_features(
1283-
tx.clone(),
1284-
&accounts,
1285-
&mut error_counters,
1286-
Some(&[simplify_writable_program_account_check::id()]),
1287-
);
1288-
1289-
assert_eq!(error_counters.invalid_writable_account, 1);
1290-
assert_eq!(loaded_accounts.len(), 1);
1291-
assert_eq!(
1292-
loaded_accounts[0],
1293-
(Err(TransactionError::InvalidWritableAccount), None)
1294-
);
1295-
1296-
// Solution 0: Include feature simplify_writable_program_account_check
1297-
let loaded_accounts =
1298-
load_accounts_with_excluded_features(tx, &accounts, &mut error_counters, None);
1299-
1300-
assert_eq!(error_counters.invalid_writable_account, 1);
1301-
assert_eq!(loaded_accounts.len(), 1);
1302-
1303-
// Solution 1: include bpf_loader_upgradeable account
1304-
let mut account = AccountSharedData::new(40, 1, &native_loader::id()); // create mock bpf_loader_upgradeable
1305-
account.set_executable(true);
1306-
account.set_rent_epoch(1);
1307-
let accounts_with_upgradeable_loader = vec![
1308-
accounts[0].clone(),
1309-
accounts[1].clone(),
1310-
(bpf_loader_upgradeable::id(), account),
1311-
];
1312-
message.account_keys = vec![key0, key1, bpf_loader_upgradeable::id()];
1313-
let tx = Transaction::new(&[&keypair], message.clone(), Hash::default());
1314-
let loaded_accounts = load_accounts_with_excluded_features(
1315-
tx,
1316-
&accounts_with_upgradeable_loader,
1317-
&mut error_counters,
1318-
Some(&[simplify_writable_program_account_check::id()]),
1319-
);
1320-
1321-
assert_eq!(error_counters.invalid_writable_account, 1);
1322-
assert_eq!(loaded_accounts.len(), 1);
1323-
let result = loaded_accounts[0].0.as_ref().unwrap();
1324-
assert_eq!(result.accounts[..2], accounts_with_upgradeable_loader[..2]);
1325-
assert_eq!(
1326-
result.accounts[result.program_indices[0][0] as usize],
1327-
accounts_with_upgradeable_loader[2]
1328-
);
1329-
1330-
// Solution 2: mark programdata as readonly
1331-
message.account_keys = vec![key0, key1, key2]; // revert key change
1332-
message.header.num_readonly_unsigned_accounts = 2; // extend readonly set to include programdata
1333-
let tx = Transaction::new(&[&keypair], message, Hash::default());
1334-
let loaded_accounts = load_accounts_with_excluded_features(
1335-
tx,
1336-
&accounts,
1337-
&mut error_counters,
1338-
Some(&[simplify_writable_program_account_check::id()]),
1339-
);
1340-
1341-
assert_eq!(error_counters.invalid_writable_account, 1);
1342-
assert_eq!(loaded_accounts.len(), 1);
1343-
let result = loaded_accounts[0].0.as_ref().unwrap();
1344-
assert_eq!(result.accounts[..2], accounts[..2]);
1345-
assert_eq!(
1346-
result.accounts[result.program_indices[0][0] as usize],
1347-
accounts[2]
1348-
);
1349-
}
1350-
13511006
fn load_accounts_no_store(
13521007
accounts: &Accounts,
13531008
tx: Transaction,

0 commit comments

Comments
 (0)