Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PoX-4 Locking via Special Contract-Call Handler #4106

Merged
merged 20 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions clarity/src/vm/database/structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,12 @@ impl ClarityDeserializable<STXBalance> for STXBalance {
unlock_height,
}
}
} else if bytes.len() == STXBalance::v2_and_v3_size {
} else if bytes.len() == STXBalance::v2_to_v4_size {
let version = &bytes[0];
if version != &STXBalance::pox_2_version && version != &STXBalance::pox_3_version {
if version != &STXBalance::pox_2_version
&& version != &STXBalance::pox_3_version
&& version != &STXBalance::pox_4_version
{
panic!(
"Bad version byte in STX Balance serialization = {}",
version
Expand Down Expand Up @@ -331,7 +334,9 @@ impl ClarityDeserializable<STXBalance> for STXBalance {
unlock_height,
}
} else {
unreachable!("Version is checked for pox_3 or pox_2 version compliance above");
unreachable!(
"Version is checked for pox_4, pox_3 or pox_2 version compliance above"
);
}
} else {
panic!("Bad STX Balance serialization size = {}", bytes.len());
Expand Down Expand Up @@ -902,7 +907,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> {
// NOTE: do _not_ add mutation methods to this struct. Put them in STXBalanceSnapshot!
impl STXBalance {
pub const unlocked_and_v1_size: usize = 40;
pub const v2_and_v3_size: usize = 41;
pub const v2_to_v4_size: usize = 41;
pub const pox_2_version: u8 = 0;
pub const pox_3_version: u8 = 1;
pub const pox_4_version: u8 = 2;
Expand Down
2 changes: 1 addition & 1 deletion pox-locking/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ fn create_event_info_data_code(function_name: &str, args: &[Value]) -> String {
/// Synthesize an events data tuple to return on the successful execution of a pox-2 or pox-3 stacking
/// function. It runs a series of Clarity queries against the PoX contract's data space (including
/// calling PoX functions).
pub fn synthesize_pox_2_or_3_event_info(
pub fn synthesize_pox_event_info(
global_context: &mut GlobalContext,
contract_id: &QualifiedContractIdentifier,
sender_opt: Option<&PrincipalData>,
Expand Down
25 changes: 25 additions & 0 deletions pox-locking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod events;
mod pox_1;
mod pox_2;
mod pox_3;
mod pox_4;

#[derive(Debug)]
pub enum LockingError {
Expand All @@ -52,6 +53,7 @@ pub enum LockingError {
pub const POX_1_NAME: &str = "pox";
pub const POX_2_NAME: &str = "pox-2";
pub const POX_3_NAME: &str = "pox-3";
pub const POX_4_NAME: &str = "pox-4";

/// Handle special cases of contract-calls -- namely, those into PoX that should lock up STX
pub fn handle_contract_call_special_cases(
Expand Down Expand Up @@ -105,6 +107,20 @@ pub fn handle_contract_call_special_cases(
result,
);
} else if *contract_id == boot_code_id(POX_3_NAME, global_context.mainnet) {
if !pox_3::is_read_only(function_name) && global_context.epoch_id >= StacksEpochId::Epoch25
{
warn!("PoX-3 function call attempted on an account after Epoch 2.5";
"v3_unlock_ht" => global_context.database.get_v3_unlock_height(),
"current_burn_ht" => global_context.database.get_current_burnchain_block_height(),
"function_name" => function_name,
"contract_id" => %contract_id
);
return Err(ClarityError::Runtime(
RuntimeErrorType::DefunctPoxContract,
None,
));
}

return pox_3::handle_contract_call(
global_context,
sender,
Expand All @@ -113,6 +129,15 @@ pub fn handle_contract_call_special_cases(
args,
result,
);
} else if *contract_id == boot_code_id(POX_4_NAME, global_context.mainnet) {
return pox_4::handle_contract_call(
global_context,
sender,
contract_id,
function_name,
args,
result,
);
}

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions pox-locking/src/pox_2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use clarity::vm::{Environment, Value};
use slog::{slog_debug, slog_error};
use stacks_common::{debug, error};

use crate::events::synthesize_pox_2_or_3_event_info;
use crate::events::synthesize_pox_event_info;
use crate::LockingError;

/// is a PoX-2 function call read only?
Expand Down Expand Up @@ -478,7 +478,7 @@ pub fn handle_contract_call(
// for some reason.
// Failure to synthesize an event due to a bug is *NOT* an excuse to crash the whole
// network! Event capture is not consensus-critical.
let event_info_opt = match synthesize_pox_2_or_3_event_info(
let event_info_opt = match synthesize_pox_event_info(
global_context,
contract_id,
sender_opt,
Expand Down
31 changes: 29 additions & 2 deletions pox-locking/src/pox_3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,40 @@ use clarity::vm::{Environment, Value};
use slog::{slog_debug, slog_error};
use stacks_common::{debug, error};

use crate::events::synthesize_pox_2_or_3_event_info;
use crate::events::synthesize_pox_event_info;
// Note: PoX-3 uses the same contract-call result parsing routines as PoX-2
use crate::pox_2::{parse_pox_extend_result, parse_pox_increase, parse_pox_stacking_result};
use crate::{LockingError, POX_3_NAME};

/////////////////////// PoX-3 /////////////////////////////////

/// is a PoX-3 function call read only?
pub(crate) fn is_read_only(func_name: &str) -> bool {
"get-pox-rejection" == func_name
|| "is-pox-active" == func_name
|| "burn-height-to-reward-cycle" == func_name
|| "reward-cycle-to-burn-height" == func_name
|| "current-pox-reward-cycle" == func_name
|| "get-stacker-info" == func_name
|| "get-check-delegation" == func_name
|| "get-reward-set-size" == func_name
|| "next-cycle-rejection-votes" == func_name
|| "get-total-ustx-stacked" == func_name
|| "get-reward-set-pox-address" == func_name
|| "get-stacking-minimum" == func_name
|| "check-pox-addr-version" == func_name
|| "check-pox-addr-hashbytes" == func_name
|| "check-pox-lock-period" == func_name
|| "can-stack-stx" == func_name
|| "minimal-can-stack-stx" == func_name
|| "get-pox-info" == func_name
|| "get-delegation-info" == func_name
|| "get-allowance-contract-callers" == func_name
|| "get-num-reward-set-pox-addresses" == func_name
|| "get-partial-stacked-by-cycle" == func_name
|| "get-total-pox-rejection" == func_name
}

/// Lock up STX for PoX for a time. Does NOT touch the account nonce.
pub fn pox_lock_v3(
db: &mut ClarityDatabase,
Expand Down Expand Up @@ -360,7 +387,7 @@ pub fn handle_contract_call(
// for some reason.
// Failure to synthesize an event due to a bug is *NOT* an excuse to crash the whole
// network! Event capture is not consensus-critical.
let event_info_opt = match synthesize_pox_2_or_3_event_info(
let event_info_opt = match synthesize_pox_event_info(
global_context,
contract_id,
sender_opt,
Expand Down
Loading