mirror of
https://github.com/d0zingcat/ore.git
synced 2026-06-04 23:26:47 +00:00
Make boosts mandatory (#121)
* make boosts mandatory * make boosts mandatory * fix account loading * cleanup * cleanup * bump version * nullify reward for invalid boosts
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -1266,7 +1266,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ore-api"
|
name = "ore-api"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-const-fn-init",
|
"array-const-fn-init",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -1323,11 +1323,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ore-program"
|
name = "ore-program"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"drillx",
|
"drillx",
|
||||||
"mpl-token-metadata",
|
"mpl-token-metadata",
|
||||||
"ore-api 3.4.0",
|
"ore-api 3.5.0",
|
||||||
"ore-boost-api 3.0.0",
|
"ore-boost-api 3.0.0",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"solana-program",
|
"solana-program",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = ["api", "program"]
|
members = ["api", "program"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://ore.supply"
|
homepage = "https://ore.supply"
|
||||||
|
|||||||
@@ -56,22 +56,21 @@ pub fn mine(
|
|||||||
authority: Pubkey,
|
authority: Pubkey,
|
||||||
bus: Pubkey,
|
bus: Pubkey,
|
||||||
solution: Solution,
|
solution: Solution,
|
||||||
boost_keys: Option<[Pubkey; 2]>,
|
boost: Pubkey,
|
||||||
|
boost_config: Pubkey,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
let proof = proof_pda(authority).0;
|
let proof = proof_pda(authority).0;
|
||||||
let mut accounts = vec![
|
let accounts = vec![
|
||||||
AccountMeta::new(signer, true),
|
AccountMeta::new(signer, true),
|
||||||
AccountMeta::new(bus, false),
|
AccountMeta::new(bus, false),
|
||||||
AccountMeta::new_readonly(CONFIG_ADDRESS, false),
|
AccountMeta::new_readonly(CONFIG_ADDRESS, false),
|
||||||
AccountMeta::new(proof, false),
|
AccountMeta::new(proof, false),
|
||||||
AccountMeta::new_readonly(sysvar::instructions::ID, false),
|
AccountMeta::new_readonly(sysvar::instructions::ID, false),
|
||||||
AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
|
AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
|
||||||
|
AccountMeta::new_readonly(boost, false),
|
||||||
|
AccountMeta::new(proof_pda(boost).0, false),
|
||||||
|
AccountMeta::new_readonly(boost_config, false),
|
||||||
];
|
];
|
||||||
if let Some([boost_address, boost_config_address]) = boost_keys {
|
|
||||||
accounts.push(AccountMeta::new_readonly(boost_address, false));
|
|
||||||
accounts.push(AccountMeta::new(proof_pda(boost_address).0, false));
|
|
||||||
accounts.push(AccountMeta::new_readonly(boost_config_address, false));
|
|
||||||
}
|
|
||||||
Instruction {
|
Instruction {
|
||||||
program_id: crate::ID,
|
program_id: crate::ID,
|
||||||
accounts,
|
accounts,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
|
|||||||
// Load accounts.
|
// Load accounts.
|
||||||
let clock = Clock::get()?;
|
let clock = Clock::get()?;
|
||||||
let t: i64 = clock.unix_timestamp;
|
let t: i64 = clock.unix_timestamp;
|
||||||
let (required_accounts, optional_accounts) = accounts.split_at(6);
|
let (required_accounts, boost_accounts) = accounts.split_at(6);
|
||||||
let [signer_info, bus_info, config_info, proof_info, instructions_sysvar, slot_hashes_sysvar] =
|
let [signer_info, bus_info, config_info, proof_info, instructions_sysvar, slot_hashes_sysvar] =
|
||||||
required_accounts
|
required_accounts
|
||||||
else {
|
else {
|
||||||
@@ -34,7 +34,7 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
|
|||||||
.is_config()?
|
.is_config()?
|
||||||
.as_account::<Config>(&ore_api::ID)?
|
.as_account::<Config>(&ore_api::ID)?
|
||||||
.assert_err(
|
.assert_err(
|
||||||
|c| c.last_reset_at.saturating_add(EPOCH_DURATION) > t,
|
|c| t < c.last_reset_at + EPOCH_DURATION,
|
||||||
OreError::NeedsReset.into(),
|
OreError::NeedsReset.into(),
|
||||||
)?;
|
)?;
|
||||||
let proof = proof_info
|
let proof = proof_info
|
||||||
@@ -46,6 +46,16 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
|
|||||||
instructions_sysvar.is_sysvar(&sysvar::instructions::ID)?;
|
instructions_sysvar.is_sysvar(&sysvar::instructions::ID)?;
|
||||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||||
|
|
||||||
|
// Load boost accounts.
|
||||||
|
let [boost_info, boost_proof_info, boost_config_info] = boost_accounts else {
|
||||||
|
return Err(ProgramError::NotEnoughAccountKeys);
|
||||||
|
};
|
||||||
|
let boost = boost_info.as_account::<Boost>(&ore_boost_api::ID)?;
|
||||||
|
let boost_config = boost_config_info.as_account::<BoostConfig>(&ore_boost_api::ID)?;
|
||||||
|
let boost_proof = boost_proof_info
|
||||||
|
.as_account_mut::<Proof>(&ore_api::ID)?
|
||||||
|
.assert_mut(|p| p.authority == *boost_info.key)?;
|
||||||
|
|
||||||
// Authenticate the proof account.
|
// Authenticate the proof account.
|
||||||
//
|
//
|
||||||
// Only one proof account can be used for any given transaction. All `mine` instructions
|
// Only one proof account can be used for any given transaction. All `mine` instructions
|
||||||
@@ -88,32 +98,27 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
|
|||||||
let normalized_difficulty = difficulty
|
let normalized_difficulty = difficulty
|
||||||
.checked_sub(config.min_difficulty as u32)
|
.checked_sub(config.min_difficulty as u32)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let base_reward = config
|
let mut base_reward = config
|
||||||
.base_reward_rate
|
.base_reward_rate
|
||||||
.checked_mul(2u64.checked_pow(normalized_difficulty).unwrap())
|
.checked_mul(2u64.checked_pow(normalized_difficulty).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Nullify base reward if boost is invalid.
|
||||||
|
if boost_config.current != *boost_info.key || t >= boost_config.ts + ROTATION_DURATION {
|
||||||
|
base_reward = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply boosts.
|
// Apply boosts.
|
||||||
//
|
//
|
||||||
// Boosts are staking incentives that can multiply a miner's rewards. The boost rewards are
|
// Boosts are staking incentives that can multiply a miner's rewards. The boost rewards are
|
||||||
// split between the miner and staker.
|
// split between the miner and staker.
|
||||||
let mut boost_reward = 0;
|
let mut boost_reward = 0;
|
||||||
if let [boost_info, _boost_proof_info, boost_config_info] = optional_accounts {
|
if t < boost.expires_at {
|
||||||
// Load boost accounts.
|
boost_reward = (base_reward as u128)
|
||||||
let boost = boost_info.as_account::<Boost>(&ore_boost_api::ID)?;
|
.checked_mul(boost.multiplier as u128)
|
||||||
let boost_config = boost_config_info.as_account::<BoostConfig>(&ore_boost_api::ID)?;
|
.unwrap()
|
||||||
|
.checked_div(DENOMINATOR_MULTIPLIER as u128)
|
||||||
// Apply multiplier if boost is active, not expired, and last rotation was less than one minute ago
|
.unwrap() as u64;
|
||||||
if boost_config.current == *boost_info.key
|
|
||||||
&& t < boost_config.ts + ROTATION_DURATION
|
|
||||||
&& t < boost.expires_at
|
|
||||||
{
|
|
||||||
boost_reward = (base_reward as u128)
|
|
||||||
.checked_mul(boost.multiplier as u128)
|
|
||||||
.unwrap()
|
|
||||||
.checked_div(DENOMINATOR_MULTIPLIER as u128)
|
|
||||||
.unwrap() as u64;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply liveness penalty.
|
// Apply liveness penalty.
|
||||||
@@ -198,19 +203,14 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
|
|||||||
|
|
||||||
// Update staker balances.
|
// Update staker balances.
|
||||||
if net_staker_boost_reward > 0 {
|
if net_staker_boost_reward > 0 {
|
||||||
if let [boost_info, boost_proof_info, _boost_config_info] = optional_accounts {
|
boost_proof.balance = boost_proof
|
||||||
let boost_proof = boost_proof_info
|
.balance
|
||||||
.as_account_mut::<Proof>(&ore_api::ID)?
|
.checked_add(net_staker_boost_reward)
|
||||||
.assert_mut(|p| p.authority == *boost_info.key)?;
|
.unwrap();
|
||||||
boost_proof.balance = boost_proof
|
boost_proof.total_rewards = boost_proof
|
||||||
.balance
|
.total_rewards
|
||||||
.checked_add(net_staker_boost_reward)
|
.checked_add(net_staker_boost_reward)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
boost_proof.total_rewards = boost_proof
|
|
||||||
.total_rewards
|
|
||||||
.checked_add(net_staker_boost_reward)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash a recent slot hash into the next challenge to prevent pre-mining attacks.
|
// Hash a recent slot hash into the next challenge to prevent pre-mining attacks.
|
||||||
|
|||||||
Reference in New Issue
Block a user