Skip to content

Commit

Permalink
requirements for configuring nakamoto-neon via CLI/toml
Browse files Browse the repository at this point in the history
  • Loading branch information
kantai committed Dec 12, 2023
1 parent 16bb688 commit 390dffc
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 36 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ members = [
# Dependencies we want to keep the same between workspace members
[workspace.dependencies]
wsts = "5.0"
rand_core = "0.6"
rand = "0.8"

# Use a bit more than default optimization for
# dev builds to speed up test execution
Expand Down
3 changes: 1 addition & 2 deletions testnet/stacks-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ rust-version = "1.61"
[dependencies]
lazy_static = "1.4.0"
pico-args = "0.3.1"
rand = "0.7.3"
serde = "1"
serde_derive = "1"
serde_json = { version = "1.0", features = ["arbitrary_precision", "raw_value"] }
Expand All @@ -29,7 +28,7 @@ chrono = "0.4.19"
regex = "1"
libsigner = { path = "../../libsigner" }
wsts = { workspace = true }
rand_core = "0.6"
rand = { workspace = true }

[dev-dependencies]
ring = "0.16.19"
Expand Down
7 changes: 6 additions & 1 deletion testnet/stacks-node/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,11 @@ impl Config {
.as_ref()
.map(|x| Secp256k1PrivateKey::from_hex(x))
.transpose()?,
self_signing_key: None,
self_signing_key: miner
.self_signing_seed
.as_ref()
.map(|x| SelfSigner::from_seed(*x))
.or(miner_default_config.self_signing_key),
},
None => miner_default_config,
};
Expand Down Expand Up @@ -2300,6 +2304,7 @@ pub struct MinerConfigFile {
pub candidate_retry_cache_size: Option<u64>,
pub unprocessed_block_deadline_secs: Option<u64>,
pub mining_key: Option<String>,
pub self_signing_seed: Option<u64>,
}

#[derive(Clone, Deserialize, Default, Debug)]
Expand Down
7 changes: 6 additions & 1 deletion testnet/stacks-node/src/keychain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ impl Keychain {
Hash160::from_node_public_key(&pk)
}

/// Get the secrete key of the nakamoto mining key
/// Get the secret key of the nakamoto mining key
pub fn get_nakamoto_sk(&self) -> &Secp256k1PrivateKey {
&self.nakamoto_mining_key
}

/// Set the secret key of the nakamoto mining key
pub fn set_nakamoto_sk(&mut self, mining_key: Secp256k1PrivateKey) {
self.nakamoto_mining_key = mining_key;
}

/// Create a default keychain from the seed, with a default nakamoto mining key derived
/// from the same seed (
pub fn default(seed: Vec<u8>) -> Keychain {
Expand Down
13 changes: 11 additions & 2 deletions testnet/stacks-node/src/mockamoto/signer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rand::{CryptoRng, RngCore, SeedableRng};
use stacks::chainstate::nakamoto::NakamotoBlock;
use stacks::chainstate::stacks::ThresholdSignature;
use wsts::curve::point::Point;
Expand All @@ -22,9 +23,17 @@ pub struct SelfSigner {
}

impl SelfSigner {
pub fn from_seed(seed: u64) -> Self {
let rng = rand::rngs::StdRng::seed_from_u64(seed);
Self::from_rng::<rand::rngs::StdRng>(rng)
}

pub fn single_signer() -> Self {
let mut rng = rand_core::OsRng::default();
let rng = rand::rngs::OsRng::default();
Self::from_rng::<rand::rngs::OsRng>(rng)
}

fn from_rng<RNG: RngCore + CryptoRng>(mut rng: RNG) -> Self {
// Create the parties
let mut signer_parties = [wsts::v2::Party::new(0, &[0], 1, 1, 1, &mut rng)];

Expand Down Expand Up @@ -54,7 +63,7 @@ impl SelfSigner {
}

pub fn sign_nakamoto_block(&mut self, block: &mut NakamotoBlock) {
let mut rng = rand_core::OsRng;
let mut rng = rand::rngs::OsRng::default();
let msg = block
.header
.signer_signature_hash()
Expand Down
14 changes: 12 additions & 2 deletions testnet/stacks-node/src/nakamoto_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use std::thread::JoinHandle;
use stacks::burnchains::{BurnchainSigner, Txid};
use stacks::chainstate::burn::db::sortdb::SortitionDB;
use stacks::chainstate::burn::BlockSnapshot;
use stacks::chainstate::stacks::Error as ChainstateError;
use stacks::monitoring;
use stacks::monitoring::update_active_miners_count_gauge;
use stacks::net::atlas::AtlasConfig;
Expand Down Expand Up @@ -88,6 +89,11 @@ pub enum Error {
BurnchainSubmissionFailed,
/// A new parent has been discovered since mining started
NewParentDiscovered,
/// A failure occurred while constructing a VRF Proof
BadVrfConstruction,
CannotSelfSign,
MiningFailure(ChainstateError),
SigningError(&'static str),
// The thread that we tried to send to has closed
ChannelClosed,
}
Expand Down Expand Up @@ -125,7 +131,10 @@ impl StacksNode {
let is_miner = runloop.is_miner();
let burnchain = runloop.get_burnchain();
let atlas_config = config.atlas.clone();
let keychain = Keychain::default(config.node.seed.clone());
let mut keychain = Keychain::default(config.node.seed.clone());
if let Some(mining_key) = config.miner.mining_key.clone() {
keychain.set_nakamoto_sk(mining_key);
}

// we can call _open_ here rather than _connect_, since connect is first called in
// make_genesis_block
Expand Down Expand Up @@ -166,7 +175,8 @@ impl StacksNode {
};
globals.set_initial_leader_key_registration_state(leader_key_registration_state);

let relayer_thread = RelayerThread::new(runloop, local_peer.clone(), relayer);
let relayer_thread =
RelayerThread::new(runloop, local_peer.clone(), relayer, keychain.clone());

StacksNode::set_monitoring_miner_address(&keychain, &relayer_thread);

Expand Down
52 changes: 32 additions & 20 deletions testnet/stacks-node/src/nakamoto_node/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,12 @@ impl BlockMinerThread {
}

// now, actually run this tenure
let Some(new_block) = self.mine_block() else {
warn!("Failed to mine block");
return;
let new_block = match self.mine_block() {
Ok(x) => x,
Err(e) => {
warn!("Failed to mine block: {e:?}");
return;
}
};

if let Some(self_signer) = self.config.self_signing() {
Expand Down Expand Up @@ -196,10 +199,11 @@ impl BlockMinerThread {
parent_tenure_consensus_hash: ConsensusHash,
parent_tenure_blocks: u64,
miner_pkh: Hash160,
) -> Option<StacksTransaction> {
) -> Result<StacksTransaction, NakamotoNodeError> {
if self.config.self_signing().is_none() {
// if we're not self-signing, then we can't generate a tenure change tx: it has to come from the signers.
return None;
warn!("Tried to generate a tenure change transaction, but we aren't self-signing");
return Err(NakamotoNodeError::CannotSelfSign);
}
let is_mainnet = self.config.is_mainnet();
let chain_id = self.config.burnchain.chain_id;
Expand Down Expand Up @@ -232,7 +236,7 @@ impl BlockMinerThread {
let mut tx_signer = StacksTransactionSigner::new(&tx);
self.keychain.sign_as_origin(&mut tx_signer);

Some(tx_signer.get_tx().unwrap())
Ok(tx_signer.get_tx().unwrap())
}

/// Create a coinbase transaction.
Expand Down Expand Up @@ -279,7 +283,7 @@ impl BlockMinerThread {
&self,
burn_db: &mut SortitionDB,
chain_state: &mut StacksChainState,
) -> Option<ParentStacksBlockInfo> {
) -> Result<ParentStacksBlockInfo, NakamotoNodeError> {
let Some(stacks_tip) =
NakamotoChainState::get_canonical_block_header(chain_state.db(), burn_db)
.expect("FATAL: could not query chain tip")
Expand All @@ -296,7 +300,7 @@ impl BlockMinerThread {
burnchain_params.first_block_timestamp.into(),
);

return Some(ParentStacksBlockInfo {
return Ok(ParentStacksBlockInfo {
parent_tenure: Some(ParentTenureInfo {
parent_tenure_consensus_hash: chain_tip.metadata.consensus_hash,
parent_tenure_blocks: 0,
Expand All @@ -319,12 +323,12 @@ impl BlockMinerThread {
&self.parent_tenure_id,
stacks_tip,
) {
Ok(parent_info) => Some(parent_info),
Ok(parent_info) => Ok(parent_info),
Err(NakamotoNodeError::BurnchainTipChanged) => {
self.globals.counters.bump_missed_tenures();
None
Err(NakamotoNodeError::BurnchainTipChanged)
}
Err(..) => None,
Err(e) => Err(e),
}
}

Expand Down Expand Up @@ -361,7 +365,7 @@ impl BlockMinerThread {
/// burnchain block-commit transaction. If we succeed, then return the assembled block data as
/// well as the microblock private key to use to produce microblocks.
/// Return None if we couldn't build a block for whatever reason.
fn mine_block(&mut self) -> Option<NakamotoBlock> {
fn mine_block(&mut self) -> Result<NakamotoBlock, NakamotoNodeError> {
debug!("block miner thread ID is {:?}", thread::current().id());
neon_node::fault_injection_long_tenure();

Expand All @@ -383,18 +387,20 @@ impl BlockMinerThread {

let target_epoch_id =
SortitionDB::get_stacks_epoch(burn_db.conn(), self.burn_block.block_height + 1)
.ok()?
.map_err(|_| NakamotoNodeError::SnapshotNotFoundForChainTip)?
.expect("FATAL: no epoch defined")
.epoch_id;
let mut parent_block_info = self.load_block_parent_info(&mut burn_db, &mut chain_state)?;
let vrf_proof = self.make_vrf_proof()?;
let vrf_proof = self
.make_vrf_proof()
.ok_or_else(|| NakamotoNodeError::BadVrfConstruction)?;

if self.last_mined_blocks.is_empty() {
if parent_block_info.parent_tenure.is_none() {
warn!(
"Miner should be starting a new tenure, but failed to load parent tenure info"
);
return None;
return Err(NakamotoNodeError::ParentNotFound);
}
}

Expand Down Expand Up @@ -452,14 +458,20 @@ impl BlockMinerThread {
Ok(block) => block,
Err(e) => {
error!("Relayer: Failure mining anchored block: {}", e);
return None;
return Err(NakamotoNodeError::MiningFailure(e));
}
};

let mining_key = self.keychain.get_nakamoto_sk();
let miner_signature = mining_key
.sign(block.header.signature_hash().ok()?.as_bytes())
.ok()?;
.sign(
block
.header
.signature_hash()
.map_err(|_| NakamotoNodeError::SigningError("Could not create sighash"))?
.as_bytes(),
)
.map_err(NakamotoNodeError::SigningError)?;
block.header.miner_signature = miner_signature;

info!(
Expand All @@ -483,10 +495,10 @@ impl BlockMinerThread {
if cur_burn_chain_tip.consensus_hash != block.header.consensus_hash {
info!("Miner: Cancel block assembly; burnchain tip has changed");
self.globals.counters.bump_missed_tenures();
return None;
return Err(NakamotoNodeError::BurnchainTipChanged);
}

Some(block)
Ok(block)
}
}

Expand Down
8 changes: 6 additions & 2 deletions testnet/stacks-node/src/nakamoto_node/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ pub struct RelayerThread {
impl RelayerThread {
/// Instantiate relayer thread.
/// Uses `runloop` to obtain globals, config, and `is_miner`` status
pub fn new(runloop: &RunLoop, local_peer: LocalPeer, relayer: Relayer) -> RelayerThread {
pub fn new(
runloop: &RunLoop,
local_peer: LocalPeer,
relayer: Relayer,
keychain: Keychain,
) -> RelayerThread {
let config = runloop.config().clone();
let globals = runloop.get_globals();
let burn_db_path = config.get_burn_db_file_path();
Expand All @@ -178,7 +183,6 @@ impl RelayerThread {
.connect_mempool_db()
.expect("Database failure opening mempool");

let keychain = Keychain::default(config.node.seed.clone());
let bitcoin_controller = BitcoinRegtestController::new_dummy(config.clone());

RelayerThread {
Expand Down
3 changes: 2 additions & 1 deletion testnet/stacks-node/src/run_loop/nakamoto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,8 @@ impl RunLoop {
.take()
.expect("Run loop already started, can only start once after initialization.");

neon::RunLoop::setup_termination_handler(self.should_keep_running.clone());
// setup the termination handler, allow it to error if a prior runloop already set it
neon::RunLoop::setup_termination_handler(self.should_keep_running.clone(), true);
let mut burnchain = neon::RunLoop::instantiate_burnchain_state(
&self.config,
self.should_keep_running.clone(),
Expand Down
7 changes: 4 additions & 3 deletions testnet/stacks-node/src/run_loop/neon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ impl RunLoop {

/// Set up termination handler. Have a signal set the `should_keep_running` atomic bool to
/// false. Panics of called more than once.
pub fn setup_termination_handler(keep_running_writer: Arc<AtomicBool>) {
pub fn setup_termination_handler(keep_running_writer: Arc<AtomicBool>, allow_err: bool) {
let install = termination::set_handler(move |sig_id| match sig_id {
SignalId::Bus => {
let msg = "Caught SIGBUS; crashing immediately and dumping core\n";
Expand All @@ -313,7 +313,8 @@ impl RunLoop {

if let Err(e) = install {
// integration tests can do this
if cfg!(test) {
if cfg!(test) || allow_err {
info!("Error setting up signal handler, may have already been set");
} else {
panic!("FATAL: error setting termination handler - {}", e);
}
Expand Down Expand Up @@ -974,7 +975,7 @@ impl RunLoop {
.take()
.expect("Run loop already started, can only start once after initialization.");

Self::setup_termination_handler(self.should_keep_running.clone());
Self::setup_termination_handler(self.should_keep_running.clone(), false);
let mut burnchain = Self::instantiate_burnchain_state(
&self.config,
self.should_keep_running.clone(),
Expand Down

0 comments on commit 390dffc

Please sign in to comment.