|
| 1 | +use super::test_utils::*; |
1 | 2 | use crate::{ |
| 3 | + account_info::{Account, AccountInfo}, |
2 | 4 | program_error::ProgramError, |
3 | 5 | sysvars::{clock::Slot, slot_hashes::*}, |
4 | 6 | }; |
5 | | -use core::mem::{align_of, size_of}; |
| 7 | +use core::{ |
| 8 | + mem::{align_of, size_of}, |
| 9 | + ptr, |
| 10 | +}; |
| 11 | + |
6 | 12 | extern crate std; |
7 | | -use super::test_utils::*; |
| 13 | +use std::io::Write; |
8 | 14 | use std::vec::Vec; |
9 | 15 |
|
10 | 16 | #[test] |
@@ -405,3 +411,87 @@ fn test_log_function() { |
405 | 411 | // Should not panic |
406 | 412 | log(&test_hash); |
407 | 413 | } |
| 414 | + |
| 415 | +#[test] |
| 416 | +fn test_from_account_info_constructor() { |
| 417 | + std::io::stderr().flush().unwrap(); |
| 418 | + |
| 419 | + const NUM_ENTRIES: usize = 3; |
| 420 | + const START_SLOT: u64 = 1234; |
| 421 | + |
| 422 | + let mock_entries = generate_mock_entries(NUM_ENTRIES, START_SLOT, DecrementStrategy::Strictly1); |
| 423 | + let data = create_mock_data(&mock_entries); |
| 424 | + |
| 425 | + let mut aligned_backing: Vec<u64>; |
| 426 | + let acct_ptr; |
| 427 | + |
| 428 | + unsafe { |
| 429 | + let header_size = core::mem::size_of::<AccountLayout>(); |
| 430 | + let total_size = header_size + data.len(); |
| 431 | + let word_len = (total_size + 7) / 8; |
| 432 | + aligned_backing = std::vec![0u64; word_len]; |
| 433 | + let base_ptr = aligned_backing.as_mut_ptr() as *mut u8; |
| 434 | + |
| 435 | + let header_ptr = base_ptr as *mut AccountLayout; |
| 436 | + ptr::write( |
| 437 | + header_ptr, |
| 438 | + AccountLayout { |
| 439 | + borrow_state: crate::NON_DUP_MARKER, |
| 440 | + is_signer: 0, |
| 441 | + is_writable: 0, |
| 442 | + executable: 0, |
| 443 | + resize_delta: 0, |
| 444 | + key: SLOTHASHES_ID, |
| 445 | + owner: [0u8; 32], |
| 446 | + lamports: 0, |
| 447 | + data_len: data.len() as u64, |
| 448 | + }, |
| 449 | + ); |
| 450 | + |
| 451 | + ptr::copy_nonoverlapping(data.as_ptr(), base_ptr.add(header_size), data.len()); |
| 452 | + |
| 453 | + acct_ptr = base_ptr as *mut Account; |
| 454 | + } |
| 455 | + |
| 456 | + let account_info = AccountInfo { raw: acct_ptr }; |
| 457 | + |
| 458 | + let slot_hashes = SlotHashes::from_account_info(&account_info) |
| 459 | + .expect("from_account_info should succeed with well-formed data"); |
| 460 | + |
| 461 | + assert_eq!(slot_hashes.len(), NUM_ENTRIES); |
| 462 | + for (i, entry) in slot_hashes.into_iter().enumerate() { |
| 463 | + assert_eq!(entry.slot(), mock_entries[i].0); |
| 464 | + assert_eq!(entry.hash, mock_entries[i].1); |
| 465 | + } |
| 466 | +} |
| 467 | + |
| 468 | +/// Host-side sanity test: ensure the `SlotHashes::fetch()` helper compiles and |
| 469 | +/// allocates a MAX_SIZE-sized buffer without panicking. |
| 470 | +/// |
| 471 | +/// On non-Solana targets the underlying syscall is stubbed; the returned buffer |
| 472 | +/// is zero-initialized and contains zero entries. We overwrite |
| 473 | +/// that buffer with deterministic fixture data and then exercise the normal |
| 474 | +/// `SlotHashes` getters to make sure the view itself works. We do not verify |
| 475 | +/// that the syscall populated real on-chain bytes, as doing so requires an |
| 476 | +/// environment outside the scope of host `cargo test`. |
| 477 | +#[cfg(feature = "std")] |
| 478 | +#[test] |
| 479 | +fn test_fetch_allocates_buffer_host() { |
| 480 | + const START_SLOT: u64 = 500; |
| 481 | + let entries = generate_mock_entries(5, START_SLOT, DecrementStrategy::Strictly1); |
| 482 | + let data = create_mock_data(&entries); |
| 483 | + |
| 484 | + // This should allocate a 20_488-byte boxed slice and *not* panic. |
| 485 | + let mut slot_hashes = |
| 486 | + SlotHashes::<std::boxed::Box<[u8]>>::fetch().expect("fetch() should allocate"); |
| 487 | + |
| 488 | + // Overwrite the stubbed contents with known data so we can reuse the |
| 489 | + // remainder of the test harness. |
| 490 | + slot_hashes.data[..data.len()].copy_from_slice(&data); |
| 491 | + |
| 492 | + assert_eq!(slot_hashes.len(), entries.len()); |
| 493 | + for (i, entry) in slot_hashes.into_iter().enumerate() { |
| 494 | + assert_eq!(entry.slot(), entries[i].0); |
| 495 | + assert_eq!(entry.hash, entries[i].1); |
| 496 | + } |
| 497 | +} |
0 commit comments