mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-14 07:26:51 +00:00
tx introspection
This commit is contained in:
669
Cargo.lock
generated
669
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -77,6 +77,10 @@ pub const METADATA_SYMBOL: &str = "ORE";
|
||||
/// The uri for token metdata.
|
||||
pub const METADATA_URI: &str = "https://ore.supply/metadata.json";
|
||||
|
||||
/// Program id of the compute budge program.
|
||||
pub const COMPUTE_BUDGET_PROGRAM_ID: Pubkey =
|
||||
pubkey!("ComputeBudget111111111111111111111111111111");
|
||||
|
||||
/// Program id for const pda derivations
|
||||
const PROGRAM_ID: [u8; 32] = unsafe { *(&crate::id() as *const Pubkey as *const [u8; 32]) };
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ pub enum OreError {
|
||||
HashTooEasy = 2,
|
||||
#[error("The claim amount cannot be greater than the claimable rewards")]
|
||||
ClaimTooLarge = 3,
|
||||
#[error("The stake amount cannot exceed u64 size")]
|
||||
StakeTooLarge = 4,
|
||||
#[error("The clock time is invalid")]
|
||||
ClockInvalid = 5,
|
||||
ClockInvalid = 4,
|
||||
#[error("Only one hash may be validated per transaction")]
|
||||
TransactionInvalid = 5,
|
||||
#[error("The tolerance cannot exceed i64 max value")]
|
||||
ToleranceInvalid = 6,
|
||||
ToleranceOverflow = 6,
|
||||
}
|
||||
|
||||
impl From<OreError> for ProgramError {
|
||||
|
||||
@@ -262,6 +262,7 @@ pub fn mine(signer: Pubkey, bus: Pubkey, nonce: u64) -> Instruction {
|
||||
AccountMeta::new(bus, false),
|
||||
AccountMeta::new_readonly(CONFIG_ADDRESS, false),
|
||||
AccountMeta::new(proof, false),
|
||||
AccountMeta::new_readonly(sysvar::instructions::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
|
||||
],
|
||||
data: [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::mem::size_of;
|
||||
|
||||
#[allow(deprecated)]
|
||||
use solana_program::{
|
||||
account_info::AccountInfo,
|
||||
clock::Clock,
|
||||
@@ -8,17 +9,19 @@ use solana_program::{
|
||||
log::sol_log,
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
sanitize::SanitizeError,
|
||||
serialize_utils::{read_pubkey, read_u16, read_u8},
|
||||
slot_hashes::SlotHash,
|
||||
sysvar::{self, Sysvar},
|
||||
sysvar::{self, instructions::load_current_index, Sysvar},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::OreError,
|
||||
instruction::MineArgs,
|
||||
instruction::{MineArgs, OreInstruction},
|
||||
loaders::*,
|
||||
state::{Bus, Config, Proof},
|
||||
utils::AccountDeserialize,
|
||||
MIN_DIFFICULTY, ONE_MINUTE, TWO_YEARS,
|
||||
COMPUTE_BUDGET_PROGRAM_ID, MIN_DIFFICULTY, ONE_MINUTE, TWO_YEARS,
|
||||
};
|
||||
|
||||
// TODO Look into tx introspection to require 1 hash per tx
|
||||
@@ -45,14 +48,22 @@ pub fn process_mine<'a, 'info>(
|
||||
let args = MineArgs::try_from_bytes(data)?;
|
||||
|
||||
// Load accounts
|
||||
let [signer, bus_info, config_info, proof_info, slot_hashes_info] = accounts else {
|
||||
let [signer, bus_info, config_info, proof_info, instructions_sysvar, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
load_signer(signer)?;
|
||||
load_any_bus(bus_info, true)?;
|
||||
load_config(config_info, false)?;
|
||||
load_proof(proof_info, signer.key, true)?;
|
||||
load_sysvar(slot_hashes_info, sysvar::slot_hashes::id())?;
|
||||
load_sysvar(instructions_sysvar, sysvar::instructions::id())?;
|
||||
load_sysvar(slot_hashes_sysvar, sysvar::slot_hashes::id())?;
|
||||
|
||||
// Validate this is the only mine ix in the transaction
|
||||
if !validate_transaction(&instructions_sysvar.data.borrow()).unwrap_or(false) {
|
||||
return Err(OreError::TransactionInvalid.into());
|
||||
}
|
||||
|
||||
// Validate mining is not paused
|
||||
let config_data = config_info.data.borrow();
|
||||
@@ -152,7 +163,7 @@ pub fn process_mine<'a, 'info>(
|
||||
// Hash recent slot hash into the next challenge to prevent pre-mining attacks
|
||||
proof.challenge = hashv(&[
|
||||
hx.as_slice(),
|
||||
&slot_hashes_info.data.borrow()[0..size_of::<SlotHash>()],
|
||||
&slot_hashes_sysvar.data.borrow()[0..size_of::<SlotHash>()],
|
||||
])
|
||||
.0;
|
||||
|
||||
@@ -169,3 +180,83 @@ pub fn process_mine<'a, 'info>(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Require that there is only one `mine` instruction per transaction and it is called from the
|
||||
/// top level of the transaction.
|
||||
fn validate_transaction(msg: &[u8]) -> Result<bool, SanitizeError> {
|
||||
#[allow(deprecated)]
|
||||
let idx = load_current_index(msg);
|
||||
let mut c = 0;
|
||||
let num_instructions = read_u16(&mut c, msg)?;
|
||||
let pc = c;
|
||||
for i in 0..num_instructions as usize {
|
||||
c = pc + i * 2;
|
||||
c = read_u16(&mut c, msg)? as usize;
|
||||
let num_accounts = read_u16(&mut c, msg)? as usize;
|
||||
c += num_accounts * 33;
|
||||
match read_pubkey(&mut c, msg)? {
|
||||
crate::ID => {
|
||||
c += 2;
|
||||
if let Ok(ix) = OreInstruction::try_from(read_u8(&mut c, msg)?) {
|
||||
if let OreInstruction::Mine = ix {
|
||||
if i.ne(&(idx as usize)) {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
COMPUTE_BUDGET_PROGRAM_ID => {
|
||||
// Noop
|
||||
}
|
||||
_ => return Ok(false),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
// fn deserialize_instruction(index: usize, data: &[u8]) -> Result<Instruction, SanitizeError> {
|
||||
// const IS_SIGNER_BIT: usize = 0;
|
||||
// const IS_WRITABLE_BIT: usize = 1;
|
||||
|
||||
// let mut current = 0;
|
||||
// let num_instructions = read_u16(&mut current, data)?;
|
||||
// if index >= num_instructions as usize {
|
||||
// return Err(SanitizeError::IndexOutOfBounds);
|
||||
// }
|
||||
|
||||
// // index into the instruction byte-offset table.
|
||||
// current += index * 2;
|
||||
// let start = read_u16(&mut current, data)?;
|
||||
|
||||
// current = start as usize;
|
||||
// let num_accounts = read_u16(&mut current, data)?;
|
||||
// let mut accounts = Vec::with_capacity(num_accounts as usize);
|
||||
// for _ in 0..num_accounts {
|
||||
// let meta_byte = read_u8(&mut current, data)?;
|
||||
// let mut is_signer = false;
|
||||
// let mut is_writable = false;
|
||||
// if meta_byte & (1 << IS_SIGNER_BIT) != 0 {
|
||||
// is_signer = true;
|
||||
// }
|
||||
// if meta_byte & (1 << IS_WRITABLE_BIT) != 0 {
|
||||
// is_writable = true;
|
||||
// }
|
||||
// let pubkey = read_pubkey(&mut current, data)?;
|
||||
// accounts.push(AccountMeta {
|
||||
// pubkey,
|
||||
// is_signer,
|
||||
// is_writable,
|
||||
// });
|
||||
// }
|
||||
// let program_id = read_pubkey(&mut current, data)?;
|
||||
// let data_len = read_u16(&mut current, data)?;
|
||||
// let data = read_slice(&mut current, data, data_len as usize)?;
|
||||
// Ok(Instruction {
|
||||
// program_id,
|
||||
// accounts,
|
||||
// data,
|
||||
// })
|
||||
// }
|
||||
|
||||
@@ -4,8 +4,8 @@ use solana_program::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::OreError, instruction::StakeArgs, loaders::*, state::Proof, utils::AccountDeserialize,
|
||||
MINT_ADDRESS, TREASURY_ADDRESS,
|
||||
instruction::StakeArgs, loaders::*, state::Proof, utils::AccountDeserialize, MINT_ADDRESS,
|
||||
TREASURY_ADDRESS,
|
||||
};
|
||||
|
||||
pub fn process_stake<'a, 'info>(
|
||||
@@ -36,10 +36,7 @@ pub fn process_stake<'a, 'info>(
|
||||
// Update proof balance
|
||||
let mut proof_data = proof_info.data.borrow_mut();
|
||||
let proof = Proof::try_from_bytes_mut(&mut proof_data)?;
|
||||
proof.balance = proof
|
||||
.balance
|
||||
.checked_add(amount)
|
||||
.ok_or(OreError::StakeTooLarge)?;
|
||||
proof.balance = proof.balance.saturating_add(amount);
|
||||
|
||||
// Update deposit timestamp
|
||||
let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?;
|
||||
|
||||
@@ -32,10 +32,10 @@ pub fn process_update_tolerance<'a, 'info>(
|
||||
|
||||
// Overflow checks
|
||||
if args.tolerance_liveness.gt(&(i64::MAX as u64)) {
|
||||
return Err(OreError::ToleranceInvalid.into());
|
||||
return Err(OreError::ToleranceOverflow.into());
|
||||
}
|
||||
if args.tolerance_spam.gt(&(i64::MAX as u64)) {
|
||||
return Err(OreError::ToleranceInvalid.into());
|
||||
return Err(OreError::ToleranceOverflow.into());
|
||||
}
|
||||
|
||||
// Update tolerances
|
||||
|
||||
Reference in New Issue
Block a user