|
28 | 28 | create_executable_meta, is_builtin, is_executable, Account, AccountSharedData, |
29 | 29 | ReadableAccount, WritableAccount, |
30 | 30 | }, |
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}, |
37 | 32 | fee::FeeStructure, |
38 | 33 | message::SanitizedMessage, |
39 | 34 | native_loader, |
@@ -195,12 +190,9 @@ fn load_transaction_accounts( |
195 | 190 | account_overrides.and_then(|overrides| overrides.get(key)) |
196 | 191 | { |
197 | 192 | (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)) |
204 | 196 | { |
205 | 197 | // Optimization to skip loading of accounts which are only used as |
206 | 198 | // programs in top-level instructions and not passed as instruction accounts. |
@@ -275,41 +267,6 @@ fn load_transaction_accounts( |
275 | 267 | validated_fee_payer = true; |
276 | 268 | } |
277 | 269 |
|
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 | | - |
313 | 270 | if in_reward_interval |
314 | 271 | && message.is_writable(i) |
315 | 272 | && solana_stake_program::check_id(account.owner()) |
@@ -548,6 +505,7 @@ mod tests { |
548 | 505 | }, |
549 | 506 | solana_sdk::{ |
550 | 507 | account::{AccountSharedData, WritableAccount}, |
| 508 | + bpf_loader_upgradeable, |
551 | 509 | compute_budget::ComputeBudgetInstruction, |
552 | 510 | epoch_schedule::EpochSchedule, |
553 | 511 | hash::Hash, |
@@ -1045,309 +1003,6 @@ mod tests { |
1045 | 1003 | } |
1046 | 1004 | } |
1047 | 1005 |
|
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 | | - |
1351 | 1006 | fn load_accounts_no_store( |
1352 | 1007 | accounts: &Accounts, |
1353 | 1008 | tx: Transaction, |
|
0 commit comments