Add simulation detection countermeasure (#22880)
* Add simulation detection countermeasures * Add program and test using TestValidator * Remove incinerator deposit * Remove incinerator * Update Cargo.lock * Add more features to simulation bank * Update Cargo.lock per rebase Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
This commit is contained in:
28
programs/bpf/rust/simulation/Cargo.toml
Normal file
28
programs/bpf/rust/simulation/Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-simulation"
|
||||
version = "1.10.0"
|
||||
description = "Solana BPF Program Simulation Differences"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-bpf-rust-simulation"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
test-bpf = []
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.10.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-logger = { path = "../../../../logger", version = "=1.10.0" }
|
||||
solana-program-test = { path = "../../../../program-test", version = "=1.10.0" }
|
||||
solana-sdk = { path = "../../../../sdk", version = "=1.10.0" }
|
||||
solana-validator = { path = "../../../../validator", version = "=1.10.0" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
39
programs/bpf/rust/simulation/src/lib.rs
Normal file
39
programs/bpf/rust/simulation/src/lib.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
clock::Clock,
|
||||
declare_id, entrypoint,
|
||||
entrypoint::ProgramResult,
|
||||
msg,
|
||||
pubkey::Pubkey,
|
||||
sysvar::Sysvar,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
||||
declare_id!("Sim1jD5C35odT8mzctm8BWnjic8xW5xgeb5MbcbErTo");
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
|
||||
pub fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
_instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
let account_info_iter = &mut accounts.iter();
|
||||
let slot_account = next_account_info(account_info_iter)?;
|
||||
|
||||
// Slot is an u64 at the end of the structure
|
||||
let data = slot_account.data.borrow();
|
||||
let slot: u64 = u64::from_le_bytes(data[data.len() - 8..].try_into().unwrap());
|
||||
|
||||
let clock = Clock::get().unwrap();
|
||||
|
||||
msg!("next_slot is {:?} ", slot);
|
||||
msg!("clock is in slot {:?} ", clock.slot);
|
||||
if clock.slot >= slot {
|
||||
msg!("On-chain");
|
||||
} else {
|
||||
panic!("Simulation");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
41
programs/bpf/rust/simulation/tests/lib.rs
Normal file
41
programs/bpf/rust/simulation/tests/lib.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use {
|
||||
solana_bpf_rust_simulation::process_instruction,
|
||||
solana_program_test::{processor, tokio, ProgramTest},
|
||||
solana_sdk::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
pubkey::Pubkey,
|
||||
signature::Signer,
|
||||
sysvar,
|
||||
transaction::Transaction,
|
||||
},
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn no_panic() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_test = ProgramTest::new(
|
||||
"solana_bpf_rust_simulation",
|
||||
program_id,
|
||||
processor!(process_instruction),
|
||||
);
|
||||
|
||||
let mut context = program_test.start_with_context().await;
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
&[Instruction {
|
||||
program_id,
|
||||
accounts: vec![AccountMeta::new_readonly(sysvar::slot_history::id(), false)],
|
||||
data: vec![],
|
||||
}],
|
||||
Some(&context.payer.pubkey()),
|
||||
&[&context.payer],
|
||||
context.last_blockhash,
|
||||
);
|
||||
|
||||
context
|
||||
.banks_client
|
||||
.process_transaction_with_preflight(transaction)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
38
programs/bpf/rust/simulation/tests/validator.rs
Normal file
38
programs/bpf/rust/simulation/tests/validator.rs
Normal file
@ -0,0 +1,38 @@
|
||||
#![cfg(feature = "test-bpf")]
|
||||
|
||||
use {
|
||||
solana_program::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
solana_sdk::{signature::Signer, transaction::Transaction},
|
||||
solana_validator::test_validator::*,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn no_panic() {
|
||||
solana_logger::setup_with_default("solana_program_runtime=debug");
|
||||
let program_id = Pubkey::new_unique();
|
||||
|
||||
let (test_validator, payer) = TestValidatorGenesis::default()
|
||||
.add_program("solana_bpf_rust_simulation", program_id)
|
||||
.start();
|
||||
let rpc_client = test_validator.get_rpc_client();
|
||||
let blockhash = rpc_client.get_latest_blockhash().unwrap();
|
||||
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
&[Instruction {
|
||||
program_id,
|
||||
accounts: vec![AccountMeta::new_readonly(sysvar::slot_history::id(), false)],
|
||||
data: vec![],
|
||||
}],
|
||||
Some(&payer.pubkey()),
|
||||
&[&payer],
|
||||
blockhash,
|
||||
);
|
||||
|
||||
rpc_client
|
||||
.send_and_confirm_transaction(&transaction)
|
||||
.unwrap();
|
||||
}
|
Reference in New Issue
Block a user