Skip to content

Commit

Permalink
feat: improved stacking orders (#1331)
Browse files Browse the repository at this point in the history
* add some pox constants

* validate epoch 3 block

* implement stack-extend for stacking orders

* validate wallet names for stacking orders

* fix build and ui pox info

* add todo's

* refactor: rework devnet stack-extend logic

* refactor: remove dead code

* refactor: remove comment

* refactor: format

* refactor: devnet handle stacking auto-extend config

* refactor: remove dead code

* chore: remove useless mut

* chore: force update

* refactor: improve stacking_order condition

* fix: updater default stacking_orders config

---------

Co-authored-by: Hugo Caillard <911307+hugocaillard@users.noreply.github.com>
  • Loading branch information
MicaiahReid and hugocaillard authored Jan 30, 2024
1 parent 99a5be5 commit b05d453
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 93 deletions.
4 changes: 2 additions & 2 deletions components/clarinet-cli/src/generate/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,14 +415,14 @@ disable_stacks_api = false
# Send some stacking orders
[[devnet.pox_stacking_orders]]
start_at_cycle = 0
start_at_cycle = 2
duration = 12
wallet = "wallet_1"
slots = 2
btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC"
[[devnet.pox_stacking_orders]]
start_at_cycle = 1
start_at_cycle = 2
duration = 12
wallet = "wallet_2"
slots = 1
Expand Down
2 changes: 1 addition & 1 deletion components/clarinet-files/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use network_manifest::{
DEFAULT_BITCOIN_NODE_IMAGE, DEFAULT_DERIVATION_PATH, DEFAULT_DOCKER_PLATFORM,
DEFAULT_EPOCH_2_0, DEFAULT_EPOCH_2_05, DEFAULT_EPOCH_2_1, DEFAULT_EPOCH_2_2, DEFAULT_EPOCH_2_3,
DEFAULT_EPOCH_2_4, DEFAULT_EPOCH_2_5, DEFAULT_EPOCH_3_0, DEFAULT_FAUCET_MNEMONIC,
DEFAULT_POSTGRES_IMAGE, DEFAULT_STACKS_API_IMAGE, DEFAULT_STACKS_API_IMAGE_NAKA,
DEFAULT_FIRST_BURN_HEADER_HEIGHT, DEFAULT_POSTGRES_IMAGE, DEFAULT_STACKS_API_IMAGE,
DEFAULT_STACKS_EXPLORER_IMAGE, DEFAULT_STACKS_MINER_MNEMONIC, DEFAULT_STACKS_NODE_IMAGE,
DEFAULT_STACKS_NODE_IMAGE_NAKA, DEFAULT_SUBNET_API_IMAGE, DEFAULT_SUBNET_CONTRACT_ID,
DEFAULT_SUBNET_MNEMONIC, DEFAULT_SUBNET_NODE_IMAGE,
Expand Down
57 changes: 57 additions & 0 deletions components/clarinet-files/src/network_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ pub const DEFAULT_EPOCH_2_4: u64 = 104;
pub const DEFAULT_EPOCH_2_5: u64 = 105;
pub const DEFAULT_EPOCH_3_0: u64 = 121;

// Currently, the pox-4 contract has these values hardcoded:
// https://github.com/stacks-network/stacks-core/blob/e09ab931e2f15ff70f3bb5c2f4d7afb[…]42bd7bec6/stackslib/src/chainstate/stacks/boot/pox-testnet.clar
// but they may be configurable in the future.
pub const DEFAULT_POX_PREPARE_LENGTH: u64 = 4;
pub const DEFAULT_POX_REWARD_LENGTH: u64 = 10;
pub const DEFAULT_FIRST_BURN_HEADER_HEIGHT: u64 = 100;

#[derive(Serialize, Deserialize, Debug)]
pub struct NetworkManifestFile {
network: NetworkConfigFile,
Expand Down Expand Up @@ -316,6 +323,7 @@ pub struct PoxStackingOrder {
pub wallet: String,
pub slots: u64,
pub btc_address: String,
pub auto_extend: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -770,6 +778,34 @@ impl NetworkManifest {
let remapped_subnet_contract_id =
format!("{}.{}", default_deployer.stx_address, contract_id.name);

// validate that epoch 3.0 is started in a reward phase
let epoch_3_0 = devnet_config.epoch_3_0.unwrap_or(DEFAULT_EPOCH_3_0);
if !is_in_reward_phase(
DEFAULT_FIRST_BURN_HEADER_HEIGHT,
DEFAULT_POX_REWARD_LENGTH,
DEFAULT_POX_PREPARE_LENGTH,
&epoch_3_0,
) {
return Err(format!(
"Epoch 3.0 must start *during* a reward phase, not a prepare phase. Epoch 3.0 start set to: {}. Reward Cycle Length: {}. Prepare Phase Length: {}",
epoch_3_0, DEFAULT_POX_REWARD_LENGTH, DEFAULT_POX_PREPARE_LENGTH
));
}

// for stacking orders, we validate that wallet names match one of the provided accounts
if let Some(ref val) = devnet_config.pox_stacking_orders {
for (i, stacking_order) in val.iter().enumerate() {
let wallet_name = &stacking_order.wallet;
let wallet_is_in_accounts = accounts
.iter()
.any(|(account_name, _)| wallet_name == account_name);
if !wallet_is_in_accounts {
return Err(format!("Account data was not provided for the wallet ({}) listed in stacking order {}.", wallet_name, i + 1));
};
}

devnet_config.pox_stacking_orders = Some(val.clone());
}
let config = DevnetConfig {
name: devnet_config.name.take().unwrap_or("devnet".into()),
network_id: devnet_config.network_id,
Expand Down Expand Up @@ -1008,6 +1044,27 @@ fn compute_btc_address(public_key: &PublicKey, network: &BitcoinNetwork) -> Stri
btc_address.to_string()
}

// This logic was taken from stacks-core:
// https://github.com/stacks-network/stacks-core/blob/524b0e1ae9ad3c8d2d2ac37e72be4aee2c045ef8/src/burnchains/mod.rs#L513C30-L530
pub fn is_in_reward_phase(
first_block_height: u64,
reward_cycle_length: u64,
prepare_length: u64,
block_height: &u64,
) -> bool {
if block_height <= &first_block_height {
// not a reward cycle start if we're the first block after genesis.
false
} else {
let effective_height = block_height - first_block_height;
let reward_index = effective_height % reward_cycle_length;

// NOTE: first block in reward cycle is mod 1, so mod 0 is the last block in the
// prepare phase.
!(reward_index == 0 || reward_index > (reward_cycle_length - prepare_length))
}
}

#[cfg(feature = "wasm")]
fn compute_btc_address(_public_key: &PublicKey, _network: &BitcoinNetwork) -> String {
"__not_implemented__".to_string()
Expand Down
1 change: 1 addition & 0 deletions components/stacks-devnet-js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,7 @@ impl StacksDevnet {
wallet,
slots,
btc_address,
auto_extend: Some(false),
});
}
overrides.pox_stacking_orders = Some(stacking_orders);
Expand Down
Loading

0 comments on commit b05d453

Please sign in to comment.