Skip to content

Commit

Permalink
feat: Nakamoto block support for stacks-insepct try-mine
Browse files Browse the repository at this point in the history
  • Loading branch information
jbencin committed Dec 20, 2024
1 parent 5f64d2d commit 86032d5
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 85 deletions.
6 changes: 3 additions & 3 deletions stackslib/src/chainstate/nakamoto/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ use crate::util_lib::boot::boot_code_id;
use crate::util_lib::db::Error as DBError;

/// Nakamaoto tenure information
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct NakamotoTenureInfo {
/// Coinbase tx, if this is a new tenure
pub coinbase_tx: Option<StacksTransaction>,
Expand All @@ -98,8 +98,8 @@ impl NakamotoTenureInfo {
pub fn cause(&self) -> Option<TenureChangeCause> {
self.tenure_change_tx
.as_ref()
.map(|tx| tx.try_as_tenure_change().map(|payload| payload.cause))
.flatten()
.map(|tx| tx.try_as_tenure_change())?
.map(|payload| payload.cause)
}

pub fn tenure_change_tx(&self) -> Option<&StacksTransaction> {
Expand Down
164 changes: 86 additions & 78 deletions stackslib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use crate::chainstate::burn::db::sortdb::{
};
use crate::chainstate::burn::{BlockSnapshot, ConsensusHash};
use crate::chainstate::coordinator::OnChainRewardSetProvider;
use crate::chainstate::nakamoto::miner::{NakamotoBlockBuilder, NakamotoTenureInfo};
use crate::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState};
use crate::chainstate::stacks::db::blocks::StagingBlock;
use crate::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, StacksHeaderInfo};
Expand Down Expand Up @@ -406,7 +407,7 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
.map(|arg| arg.parse().expect("Could not parse max_time"))
.unwrap_or(u64::MAX);

let start = get_epoch_time_ms();
let start = Instant::now();

let conf = conf.unwrap_or(&DEFAULT_MAINNET_CONFIG);

Expand All @@ -417,7 +418,7 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
let burnchain = conf.get_burnchain();
let sort_db = SortitionDB::open(&sort_db_path, false, burnchain.pox_constants.clone())
.unwrap_or_else(|e| panic!("Failed to open {sort_db_path}: {e}"));
let (chain_state, _) = StacksChainState::open(
let (chainstate, _) = StacksChainState::open(
conf.is_mainnet(),
conf.burnchain.chain_id,
&chain_state_path,
Expand All @@ -439,93 +440,100 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
)
.unwrap_or_else(|e| panic!("Failed to open mempool db: {e}"));

let tip_header = NakamotoChainState::get_canonical_block_header(chain_state.db(), &sort_db)
.unwrap_or_else(|e| panic!("Error looking up chain tip: {e}"))
.expect("No chain tip found");
// Parent Staccks header for block we are going to mine
let parent_stacks_header =
NakamotoChainState::get_canonical_block_header(chainstate.db(), &sort_db)
.unwrap_or_else(|e| panic!("Error looking up chain tip: {e}"))
.expect("No chain tip found");

// Fail if Nakamoto chainstate detected. `try-mine` cannot mine Nakamoto blocks yet
// TODO: Add Nakamoto block support
if matches!(
&tip_header.anchored_header,
StacksBlockHeaderTypes::Nakamoto(..)
) {
panic!("Attempting to mine Nakamoto block. Nakamoto blocks not supported yet!");
};
let burn_dbconn = sort_db.index_handle(&chain_tip.sortition_id);

let sk = StacksPrivateKey::new();
let mut tx_auth = TransactionAuth::from_p2pkh(&sk).unwrap();
tx_auth.set_origin_nonce(0);
let mut settings = BlockBuilderSettings::limited();
settings.max_miner_time_ms = max_time;

let mut coinbase_tx = StacksTransaction::new(
TransactionVersion::Mainnet,
tx_auth,
TransactionPayload::Coinbase(CoinbasePayload([0u8; 32]), None, None),
);
let result = match &parent_stacks_header.anchored_header {
StacksBlockHeaderTypes::Epoch2(..) => {
let sk = StacksPrivateKey::new();
let mut tx_auth = TransactionAuth::from_p2pkh(&sk).unwrap();
tx_auth.set_origin_nonce(0);

coinbase_tx.chain_id = conf.burnchain.chain_id;
coinbase_tx.anchor_mode = TransactionAnchorMode::OnChainOnly;
let mut tx_signer = StacksTransactionSigner::new(&coinbase_tx);
tx_signer.sign_origin(&sk).unwrap();
let coinbase_tx = tx_signer.get_tx().unwrap();
let mut coinbase_tx = StacksTransaction::new(
TransactionVersion::Mainnet,
tx_auth,
TransactionPayload::Coinbase(CoinbasePayload([0u8; 32]), None, None),
);

let mut settings = BlockBuilderSettings::limited();
settings.max_miner_time_ms = max_time;
coinbase_tx.chain_id = conf.burnchain.chain_id;
coinbase_tx.anchor_mode = TransactionAnchorMode::OnChainOnly;
let mut tx_signer = StacksTransactionSigner::new(&coinbase_tx);
tx_signer.sign_origin(&sk).unwrap();
let coinbase_tx = tx_signer.get_tx().unwrap();

StacksBlockBuilder::build_anchored_block(
&chainstate,
&burn_dbconn,
&mut mempool_db,
&parent_stacks_header,
chain_tip.total_burn,
VRFProof::empty(),
Hash160([0; 20]),
&coinbase_tx,
settings,
None,
&Burnchain::new(
&burnchain_path,
&burnchain.chain_name,
&burnchain.network_name,
)
.unwrap_or_else(|e| panic!("Failed to instantiate burnchain: {e}")),
)
.map(|(block, cost, size)| (block.block_hash(), block.txs, cost, size))
}
StacksBlockHeaderTypes::Nakamoto(..) => {
NakamotoBlockBuilder::build_nakamoto_block(
&chainstate,
&burn_dbconn,
&mut mempool_db,
&parent_stacks_header,
// tenure ID consensus hash of this block
&parent_stacks_header.consensus_hash,
// the burn so far on the burnchain (i.e. from the last burnchain block)
chain_tip.total_burn,
NakamotoTenureInfo::default(),
settings,
None,
0,
)
.map(|(block, cost, size, _)| (block.header.block_hash(), block.txs, cost, size))
}
};

let result = StacksBlockBuilder::build_anchored_block(
&chain_state,
&sort_db.index_handle(&chain_tip.sortition_id),
&mut mempool_db,
&tip_header,
chain_tip.total_burn,
VRFProof::empty(),
Hash160([0; 20]),
&coinbase_tx,
settings,
None,
&Burnchain::new(
&burnchain_path,
&burnchain.chain_name,
&burnchain.network_name,
)
.unwrap(),
let elapsed = start.elapsed();
let summary = format!(
"block @ height = {h} off of {pid} ({pch}/{pbh}) in {t}ms. Min-fee: {min_fee}, Max-time: {max_time}",
h=parent_stacks_header.stacks_block_height + 1,
pid=&parent_stacks_header.index_block_hash(),
pch=&parent_stacks_header.consensus_hash,
pbh=&parent_stacks_header.anchored_header.block_hash(),
t=elapsed.as_millis(),
);

let stop = get_epoch_time_ms();

println!(
"{} mined block @ height = {} off of {} ({}/{}) in {}ms. Min-fee: {}, Max-time: {}",
if result.is_ok() {
"Successfully"
} else {
"Failed to"
},
tip_header.stacks_block_height + 1,
StacksBlockHeader::make_index_block_hash(
&tip_header.consensus_hash,
&tip_header.anchored_header.block_hash()
),
&tip_header.consensus_hash,
&tip_header.anchored_header.block_hash(),
stop.saturating_sub(start),
min_fee,
max_time
);
let code = match result {
Ok((block_hash, txs, cost, size)) => {
let total_fees: u64 = txs.iter().map(|tx| tx.get_tx_fee()).sum();

if let Ok((block, execution_cost, size)) = result {
let mut total_fees = 0;
for tx in block.txs.iter() {
total_fees += tx.get_tx_fee();
println!("Successfully mined {summary}");
println!("Block {block_hash}: {total_fees} uSTX, {size} bytes, cost {cost:?}");
0
}
println!(
"Block {}: {} uSTX, {} bytes, cost {:?}",
block.block_hash(),
total_fees,
size,
&execution_cost
);
}
Err(e) => {
println!("Failed to mine {summary}");
println!("Error: {e}");
1
}
};

process::exit(0);
process::exit(code);
}

/// Fetch and process a `StagingBlock` from database and call `replay_block()` to validate
Expand Down
6 changes: 2 additions & 4 deletions testnet/stacks-node/src/tests/nakamoto_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,8 @@ pub fn next_block_and_wait_for_commits(
.map(|x| x.load(Ordering::SeqCst))
.collect();

let mut block_processed_time: Vec<Option<Instant>> =
(0..commits_before.len()).map(|_| None).collect();
let mut commit_sent_time: Vec<Option<Instant>> =
(0..commits_before.len()).map(|_| None).collect();
let mut block_processed_time: Vec<Option<Instant>> = vec![None; commits_before.len()];
let mut commit_sent_time: Vec<Option<Instant>> = vec![None; commits_before.len()];
next_block_and(btc_controller, timeout_secs, || {
for i in 0..commits_submitted.len() {
let commits_sent = commits_submitted[i].load(Ordering::SeqCst);
Expand Down

0 comments on commit 86032d5

Please sign in to comment.