storage_processor.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. use assert_matches::assert_matches;
  2. use bincode::deserialize;
  3. use log::*;
  4. use solana_runtime::{
  5. bank::Bank,
  6. bank_client::BankClient,
  7. genesis_utils::{create_genesis_block, GenesisBlockInfo},
  8. };
  9. use solana_sdk::{
  10. account::{create_keyed_accounts, Account, KeyedAccount},
  11. account_utils::State,
  12. client::SyncClient,
  13. clock::{get_segment_from_slot, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
  14. hash::{hash, Hash},
  15. instruction::{Instruction, InstructionError},
  16. message::Message,
  17. pubkey::Pubkey,
  18. signature::{Keypair, KeypairUtil, Signature},
  19. system_instruction,
  20. sysvar::clock::{self, Clock},
  21. sysvar::rewards::{self, Rewards},
  22. };
  23. use solana_storage_api::{
  24. id,
  25. storage_contract::StorageAccount,
  26. storage_contract::{ProofStatus, StorageContract, STORAGE_ACCOUNT_SPACE},
  27. storage_instruction::{self, StorageAccountType},
  28. storage_processor::process_instruction,
  29. };
  30. use std::collections::HashMap;
  31. use std::sync::Arc;
  32. const TICKS_IN_SEGMENT: u64 = DEFAULT_SLOTS_PER_SEGMENT * DEFAULT_TICKS_PER_SLOT;
  33. fn test_instruction(
  34. ix: &Instruction,
  35. program_accounts: &mut [Account],
  36. ) -> Result<(), InstructionError> {
  37. let mut keyed_accounts: Vec<_> = ix
  38. .accounts
  39. .iter()
  40. .zip(program_accounts.iter_mut())
  41. .map(|(account_meta, account)| {
  42. KeyedAccount::new(&account_meta.pubkey, account_meta.is_signer, account)
  43. })
  44. .collect();
  45. let ret = process_instruction(&id(), &mut keyed_accounts, &ix.data);
  46. info!("ret: {:?}", ret);
  47. ret
  48. }
  49. #[test]
  50. fn test_account_owner() {
  51. let account_owner = Pubkey::new_rand();
  52. let validator_storage_pubkey = Pubkey::new_rand();
  53. let replicator_storage_pubkey = Pubkey::new_rand();
  54. let GenesisBlockInfo {
  55. genesis_block,
  56. mint_keypair,
  57. ..
  58. } = create_genesis_block(1000);
  59. let mut bank = Bank::new(&genesis_block);
  60. let mint_pubkey = mint_keypair.pubkey();
  61. bank.add_instruction_processor(id(), process_instruction);
  62. let bank = Arc::new(bank);
  63. let bank_client = BankClient::new_shared(&bank);
  64. let message = Message::new(storage_instruction::create_storage_account(
  65. &mint_pubkey,
  66. &account_owner,
  67. &validator_storage_pubkey,
  68. 1,
  69. StorageAccountType::Validator,
  70. ));
  71. bank_client
  72. .send_message(&[&mint_keypair], message)
  73. .expect("failed to create account");
  74. let account = bank
  75. .get_account(&validator_storage_pubkey)
  76. .expect("account not found");
  77. let storage_contract = account.state().expect("couldn't unpack account data");
  78. if let StorageContract::ValidatorStorage { owner, .. } = storage_contract {
  79. assert_eq!(owner, account_owner);
  80. } else {
  81. assert!(false, "wrong account type found")
  82. }
  83. let message = Message::new(storage_instruction::create_storage_account(
  84. &mint_pubkey,
  85. &account_owner,
  86. &replicator_storage_pubkey,
  87. 1,
  88. StorageAccountType::Replicator,
  89. ));
  90. bank_client
  91. .send_message(&[&mint_keypair], message)
  92. .expect("failed to create account");
  93. let account = bank
  94. .get_account(&replicator_storage_pubkey)
  95. .expect("account not found");
  96. let storage_contract = account.state().expect("couldn't unpack account data");
  97. if let StorageContract::ReplicatorStorage { owner, .. } = storage_contract {
  98. assert_eq!(owner, account_owner);
  99. } else {
  100. assert!(false, "wrong account type found")
  101. }
  102. }
  103. #[test]
  104. fn test_proof_bounds() {
  105. let account_owner = Pubkey::new_rand();
  106. let pubkey = Pubkey::new_rand();
  107. let mut account = Account {
  108. data: vec![0; STORAGE_ACCOUNT_SPACE as usize],
  109. ..Account::default()
  110. };
  111. {
  112. let mut storage_account = StorageAccount::new(pubkey, &mut account);
  113. storage_account
  114. .initialize_storage(account_owner, StorageAccountType::Replicator)
  115. .unwrap();
  116. }
  117. let ix = storage_instruction::mining_proof(
  118. &pubkey,
  119. Hash::default(),
  120. 0,
  121. Signature::default(),
  122. Hash::default(),
  123. );
  124. // the proof is for segment 0, need to move the slot into segment 2
  125. let mut clock_account = clock::new_account(1, 0, 0, 0, 0);
  126. Clock::to_account(
  127. &Clock {
  128. slot: DEFAULT_SLOTS_PER_SEGMENT * 2,
  129. segment: 2,
  130. epoch: 0,
  131. stakers_epoch: 0,
  132. },
  133. &mut clock_account,
  134. );
  135. assert_eq!(test_instruction(&ix, &mut [account, clock_account]), Ok(()));
  136. }
  137. #[test]
  138. fn test_storage_tx() {
  139. let pubkey = Pubkey::new_rand();
  140. let mut accounts = [(pubkey, Account::default())];
  141. let mut keyed_accounts = create_keyed_accounts(&mut accounts);
  142. assert!(process_instruction(&id(), &mut keyed_accounts, &[]).is_err());
  143. }
  144. #[test]
  145. fn test_serialize_overflow() {
  146. let pubkey = Pubkey::new_rand();
  147. let clock_id = clock::id();
  148. let mut keyed_accounts = Vec::new();
  149. let mut user_account = Account::default();
  150. let mut clock_account = clock::new_account(1, 0, 0, 0, 0);
  151. keyed_accounts.push(KeyedAccount::new(&pubkey, true, &mut user_account));
  152. keyed_accounts.push(KeyedAccount::new(&clock_id, false, &mut clock_account));
  153. let ix = storage_instruction::advertise_recent_blockhash(&pubkey, Hash::default(), 1);
  154. assert_eq!(
  155. process_instruction(&id(), &mut keyed_accounts, &ix.data),
  156. Err(InstructionError::InvalidAccountData)
  157. );
  158. }
  159. #[test]
  160. fn test_invalid_accounts_len() {
  161. let pubkey = Pubkey::new_rand();
  162. let mut accounts = [Account::default()];
  163. let ix = storage_instruction::mining_proof(
  164. &pubkey,
  165. Hash::default(),
  166. 0,
  167. Signature::default(),
  168. Hash::default(),
  169. );
  170. // move tick height into segment 1
  171. let mut clock_account = clock::new_account(1, 0, 0, 0, 0);
  172. Clock::to_account(
  173. &Clock {
  174. slot: 16,
  175. segment: 1,
  176. epoch: 0,
  177. stakers_epoch: 0,
  178. },
  179. &mut clock_account,
  180. );
  181. assert!(test_instruction(&ix, &mut accounts).is_err());
  182. let mut accounts = [Account::default(), clock_account, Account::default()];
  183. assert!(test_instruction(&ix, &mut accounts).is_err());
  184. }
  185. #[test]
  186. fn test_submit_mining_invalid_slot() {
  187. solana_logger::setup();
  188. let pubkey = Pubkey::new_rand();
  189. let mut accounts = [Account::default(), Account::default()];
  190. accounts[0].data.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
  191. accounts[1].data.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
  192. let ix = storage_instruction::mining_proof(
  193. &pubkey,
  194. Hash::default(),
  195. 0,
  196. Signature::default(),
  197. Hash::default(),
  198. );
  199. // submitting a proof for a slot in the past, so this should fail
  200. assert!(test_instruction(&ix, &mut accounts).is_err());
  201. }
  202. #[test]
  203. fn test_submit_mining_ok() {
  204. solana_logger::setup();
  205. let account_owner = Pubkey::new_rand();
  206. let pubkey = Pubkey::new_rand();
  207. let mut account = Account::default();
  208. account.data.resize(STORAGE_ACCOUNT_SPACE as usize, 0);
  209. {
  210. let mut storage_account = StorageAccount::new(pubkey, &mut account);
  211. storage_account
  212. .initialize_storage(account_owner, StorageAccountType::Replicator)
  213. .unwrap();
  214. }
  215. let ix = storage_instruction::mining_proof(
  216. &pubkey,
  217. Hash::default(),
  218. 0,
  219. Signature::default(),
  220. Hash::default(),
  221. );
  222. // move slot into segment 1
  223. let mut clock_account = clock::new_account(1, 0, 0, 0, 0);
  224. Clock::to_account(
  225. &Clock {
  226. slot: DEFAULT_SLOTS_PER_SEGMENT,
  227. segment: 1,
  228. epoch: 0,
  229. stakers_epoch: 0,
  230. },
  231. &mut clock_account,
  232. );
  233. assert_matches!(test_instruction(&ix, &mut [account, clock_account]), Ok(_));
  234. }
  235. #[test]
  236. fn test_validate_mining() {
  237. solana_logger::setup();
  238. let GenesisBlockInfo {
  239. mut genesis_block,
  240. mint_keypair,
  241. ..
  242. } = create_genesis_block(100_000_000_000);
  243. genesis_block
  244. .native_instruction_processors
  245. .push(solana_storage_program::solana_storage_program!());
  246. let mint_pubkey = mint_keypair.pubkey();
  247. // 1 owner for all replicator and validator accounts for the test
  248. let owner_pubkey = Pubkey::new_rand();
  249. let replicator_1_storage_keypair = Keypair::new();
  250. let replicator_1_storage_id = replicator_1_storage_keypair.pubkey();
  251. let replicator_2_storage_keypair = Keypair::new();
  252. let replicator_2_storage_id = replicator_2_storage_keypair.pubkey();
  253. let validator_storage_keypair = Keypair::new();
  254. let validator_storage_id = validator_storage_keypair.pubkey();
  255. let bank = Bank::new(&genesis_block);
  256. let bank = Arc::new(bank);
  257. let bank_client = BankClient::new_shared(&bank);
  258. init_storage_accounts(
  259. &owner_pubkey,
  260. &bank_client,
  261. &mint_keypair,
  262. &[&validator_storage_id],
  263. &[&replicator_1_storage_id, &replicator_2_storage_id],
  264. 10,
  265. );
  266. // create a new bank in segment 2
  267. let bank = Arc::new(Bank::new_from_parent(
  268. &bank,
  269. &Pubkey::default(),
  270. DEFAULT_SLOTS_PER_SEGMENT * 2,
  271. ));
  272. let bank_client = BankClient::new_shared(&bank);
  273. // advertise for storage segment 1
  274. let message = Message::new_with_payer(
  275. vec![storage_instruction::advertise_recent_blockhash(
  276. &validator_storage_id,
  277. Hash::default(),
  278. 1,
  279. )],
  280. Some(&mint_pubkey),
  281. );
  282. assert_matches!(
  283. bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
  284. Ok(_)
  285. );
  286. // submit proofs 5 proofs for each replicator for segment 0
  287. let mut checked_proofs: HashMap<_, Vec<_>> = HashMap::new();
  288. for _ in 0..5 {
  289. checked_proofs
  290. .entry(replicator_1_storage_id)
  291. .or_default()
  292. .push(submit_proof(
  293. &mint_keypair,
  294. &replicator_1_storage_keypair,
  295. &bank_client,
  296. 0,
  297. ));
  298. checked_proofs
  299. .entry(replicator_2_storage_id)
  300. .or_default()
  301. .push(submit_proof(
  302. &mint_keypair,
  303. &replicator_2_storage_keypair,
  304. &bank_client,
  305. 0,
  306. ));
  307. }
  308. let message = Message::new_with_payer(
  309. vec![storage_instruction::advertise_recent_blockhash(
  310. &validator_storage_id,
  311. Hash::default(),
  312. 2,
  313. )],
  314. Some(&mint_pubkey),
  315. );
  316. // move banks into the next segment
  317. let proof_segment = get_segment_from_slot(bank.slot(), bank.slots_per_segment());
  318. let bank = Arc::new(Bank::new_from_parent(
  319. &bank,
  320. &Pubkey::default(),
  321. DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
  322. ));
  323. let bank_client = BankClient::new_shared(&bank);
  324. assert_matches!(
  325. bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
  326. Ok(_)
  327. );
  328. let message = Message::new_with_payer(
  329. vec![storage_instruction::proof_validation(
  330. &validator_storage_id,
  331. proof_segment as u64,
  332. checked_proofs.into_iter().map(|entry| entry).collect(),
  333. )],
  334. Some(&mint_pubkey),
  335. );
  336. assert_matches!(
  337. bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
  338. Ok(_)
  339. );
  340. let message = Message::new_with_payer(
  341. vec![storage_instruction::advertise_recent_blockhash(
  342. &validator_storage_id,
  343. Hash::default(),
  344. 3,
  345. )],
  346. Some(&mint_pubkey),
  347. );
  348. // move banks into the next segment
  349. let bank = Arc::new(Bank::new_from_parent(
  350. &bank,
  351. &Pubkey::default(),
  352. DEFAULT_SLOTS_PER_SEGMENT + bank.slot(),
  353. ));
  354. let bank_client = BankClient::new_shared(&bank);
  355. assert_matches!(
  356. bank_client.send_message(&[&mint_keypair, &validator_storage_keypair], message),
  357. Ok(_)
  358. );
  359. assert_eq!(bank_client.get_balance(&validator_storage_id).unwrap(), 10);
  360. let bank = Arc::new(Bank::new_from_parent(
  361. &bank,
  362. &Pubkey::default(),
  363. bank.slot() + bank.epoch_schedule().slots_per_epoch,
  364. ));
  365. let bank_client = BankClient::new_shared(&bank);
  366. let rewards = bank
  367. .get_account(&rewards::id())
  368. .map(|account| Rewards::from_account(&account).unwrap())
  369. .unwrap();
  370. let message = Message::new_with_payer(
  371. vec![storage_instruction::claim_reward(
  372. &owner_pubkey,
  373. &validator_storage_id,
  374. )],
  375. Some(&mint_pubkey),
  376. );
  377. assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
  378. assert_eq!(
  379. bank_client.get_balance(&owner_pubkey).unwrap(),
  380. 1 + ((rewards.storage_point_value * 10_f64) as u64)
  381. );
  382. // tick the bank into the next storage epoch so that rewards can be claimed
  383. for _ in 0..=TICKS_IN_SEGMENT {
  384. bank.register_tick(&bank.last_blockhash());
  385. }
  386. assert_eq!(
  387. bank_client.get_balance(&replicator_1_storage_id).unwrap(),
  388. 10
  389. );
  390. let message = Message::new_with_payer(
  391. vec![storage_instruction::claim_reward(
  392. &owner_pubkey,
  393. &replicator_1_storage_id,
  394. )],
  395. Some(&mint_pubkey),
  396. );
  397. assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
  398. assert_eq!(
  399. bank_client.get_balance(&owner_pubkey).unwrap(),
  400. 1 + ((rewards.storage_point_value * 10_f64) as u64)
  401. + (rewards.storage_point_value * 5_f64) as u64
  402. );
  403. let message = Message::new_with_payer(
  404. vec![storage_instruction::claim_reward(
  405. &owner_pubkey,
  406. &replicator_2_storage_id,
  407. )],
  408. Some(&mint_pubkey),
  409. );
  410. assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
  411. assert_eq!(
  412. bank_client.get_balance(&owner_pubkey).unwrap(),
  413. 1 + (rewards.storage_point_value * 10_f64) as u64
  414. + (rewards.storage_point_value * 5_f64) as u64
  415. + (rewards.storage_point_value * 5_f64) as u64
  416. );
  417. }
  418. fn init_storage_accounts(
  419. owner: &Pubkey,
  420. client: &BankClient,
  421. mint: &Keypair,
  422. validator_accounts_to_create: &[&Pubkey],
  423. replicator_accounts_to_create: &[&Pubkey],
  424. lamports: u64,
  425. ) {
  426. let mut ixs: Vec<_> = vec![system_instruction::transfer_now(&mint.pubkey(), owner, 1)];
  427. ixs.append(
  428. &mut validator_accounts_to_create
  429. .into_iter()
  430. .flat_map(|account| {
  431. storage_instruction::create_storage_account(
  432. &mint.pubkey(),
  433. owner,
  434. account,
  435. lamports,
  436. StorageAccountType::Validator,
  437. )
  438. })
  439. .collect(),
  440. );
  441. replicator_accounts_to_create
  442. .into_iter()
  443. .for_each(|account| {
  444. ixs.append(&mut storage_instruction::create_storage_account(
  445. &mint.pubkey(),
  446. owner,
  447. account,
  448. lamports,
  449. StorageAccountType::Replicator,
  450. ))
  451. });
  452. let message = Message::new(ixs);
  453. client.send_message(&[mint], message).unwrap();
  454. }
  455. fn get_storage_segment<C: SyncClient>(client: &C, account: &Pubkey) -> u64 {
  456. match client.get_account_data(&account).unwrap() {
  457. Some(storage_system_account_data) => {
  458. let contract = deserialize(&storage_system_account_data);
  459. if let Ok(contract) = contract {
  460. match contract {
  461. StorageContract::ValidatorStorage { segment, .. } => {
  462. return segment;
  463. }
  464. _ => info!("error in reading segment"),
  465. }
  466. }
  467. }
  468. None => {
  469. info!("error in reading segment");
  470. }
  471. }
  472. 0
  473. }
  474. fn submit_proof(
  475. mint_keypair: &Keypair,
  476. storage_keypair: &Keypair,
  477. bank_client: &BankClient,
  478. segment_index: u64,
  479. ) -> ProofStatus {
  480. let sha_state = Hash::new(Pubkey::new_rand().as_ref());
  481. let message = Message::new_with_payer(
  482. vec![storage_instruction::mining_proof(
  483. &storage_keypair.pubkey(),
  484. sha_state,
  485. segment_index,
  486. Signature::default(),
  487. bank_client.get_recent_blockhash().unwrap().0,
  488. )],
  489. Some(&mint_keypair.pubkey()),
  490. );
  491. assert_matches!(
  492. bank_client.send_message(&[&mint_keypair, &storage_keypair], message),
  493. Ok(_)
  494. );
  495. ProofStatus::Valid
  496. }
  497. fn get_storage_blockhash<C: SyncClient>(client: &C, account: &Pubkey) -> Hash {
  498. if let Some(storage_system_account_data) = client.get_account_data(&account).unwrap() {
  499. let contract = deserialize(&storage_system_account_data);
  500. if let Ok(contract) = contract {
  501. match contract {
  502. StorageContract::ValidatorStorage { hash, .. } => {
  503. return hash;
  504. }
  505. _ => (),
  506. }
  507. }
  508. }
  509. Hash::default()
  510. }
  511. #[test]
  512. fn test_bank_storage() {
  513. let GenesisBlockInfo {
  514. mut genesis_block,
  515. mint_keypair,
  516. ..
  517. } = create_genesis_block(1000);
  518. genesis_block
  519. .native_instruction_processors
  520. .push(solana_storage_program::solana_storage_program!());
  521. let mint_pubkey = mint_keypair.pubkey();
  522. let replicator_keypair = Keypair::new();
  523. let replicator_pubkey = replicator_keypair.pubkey();
  524. let validator_keypair = Keypair::new();
  525. let validator_pubkey = validator_keypair.pubkey();
  526. let bank = Bank::new(&genesis_block);
  527. // tick the bank up until it's moved into storage segment 2
  528. // create a new bank in storage segment 2
  529. let bank = Bank::new_from_parent(
  530. &Arc::new(bank),
  531. &Pubkey::new_rand(),
  532. DEFAULT_SLOTS_PER_SEGMENT * 2,
  533. );
  534. let bank_client = BankClient::new(bank);
  535. let x = 42;
  536. let x2 = x * 2;
  537. let storage_blockhash = hash(&[x2]);
  538. let message = Message::new(storage_instruction::create_storage_account(
  539. &mint_pubkey,
  540. &Pubkey::default(),
  541. &replicator_pubkey,
  542. 11,
  543. StorageAccountType::Replicator,
  544. ));
  545. bank_client.send_message(&[&mint_keypair], message).unwrap();
  546. let message = Message::new(storage_instruction::create_storage_account(
  547. &mint_pubkey,
  548. &Pubkey::default(),
  549. &validator_pubkey,
  550. 1,
  551. StorageAccountType::Validator,
  552. ));
  553. bank_client.send_message(&[&mint_keypair], message).unwrap();
  554. let message = Message::new_with_payer(
  555. vec![storage_instruction::advertise_recent_blockhash(
  556. &validator_pubkey,
  557. storage_blockhash,
  558. 1,
  559. )],
  560. Some(&mint_pubkey),
  561. );
  562. assert_matches!(
  563. bank_client.send_message(&[&mint_keypair, &validator_keypair], message),
  564. Ok(_)
  565. );
  566. let slot = 0;
  567. let message = Message::new_with_payer(
  568. vec![storage_instruction::mining_proof(
  569. &replicator_pubkey,
  570. Hash::default(),
  571. slot,
  572. Signature::default(),
  573. bank_client.get_recent_blockhash().unwrap().0,
  574. )],
  575. Some(&mint_pubkey),
  576. );
  577. assert_matches!(
  578. bank_client.send_message(&[&mint_keypair, &replicator_keypair], message),
  579. Ok(_)
  580. );
  581. assert_eq!(get_storage_segment(&bank_client, &validator_pubkey), 1);
  582. assert_eq!(
  583. get_storage_blockhash(&bank_client, &validator_pubkey),
  584. storage_blockhash
  585. );
  586. }