diff --git a/src/vm/docs/mod.rs b/src/vm/docs/mod.rs index d1dfbbb6821..6e58dd5a665 100644 --- a/src/vm/docs/mod.rs +++ b/src/vm/docs/mod.rs @@ -545,7 +545,7 @@ const PRINT_API: SpecialAPI = SpecialAPI { input_type: "A", output_type: "A", signature: "(print expr)", - description: "The `print` function evaluates and returns its input expression. On Blockstack Core + description: "The `print` function evaluates and returns its input expression. On Stacks Core nodes configured for development (as opposed to production mining nodes), this function prints the resulting value to `STDOUT` (standard output).", example: "(print (+ 1 2 3)) ;; Returns 6", }; diff --git a/testnet/stacks-node/src/keychain.rs b/testnet/stacks-node/src/keychain.rs index 606dd63af6a..25cad75405d 100644 --- a/testnet/stacks-node/src/keychain.rs +++ b/testnet/stacks-node/src/keychain.rs @@ -7,7 +7,7 @@ use stacks::burnchains::{BurnchainSigner, PrivateKey}; use stacks::chainstate::stacks::{ StacksAddress, StacksPrivateKey, StacksPublicKey, StacksTransactionSigner, TransactionAuth, }; -use stacks::util::hash::Sha256Sum; +use stacks::util::hash::{Hash160, Sha256Sum}; use stacks::util::vrf::{VRFPrivateKey, VRFProof, VRFPublicKey, VRF}; #[derive(Clone)] @@ -97,14 +97,18 @@ impl Keychain { pk } - pub fn rotate_microblock_keypair(&mut self) -> StacksPrivateKey { - let mut seed = match self.microblocks_secret_keys.last() { + pub fn rotate_microblock_keypair(&mut self, burn_block_height: u64) -> StacksPrivateKey { + let mut secret_state = match self.microblocks_secret_keys.last() { // First key is the hash of the secret state - None => self.hashed_secret_state, + None => self.hashed_secret_state.to_bytes().to_vec(), // Next key is the hash of the last - Some(last_sk) => Sha256Sum::from_data(&last_sk.to_bytes()[..]), + Some(last_sk) => last_sk.to_bytes().to_vec(), }; + secret_state.extend_from_slice(&burn_block_height.to_be_bytes()); + + let mut seed = Sha256Sum::from_data(&secret_state); + // Not every 256-bit number is a valid secp256k1 secret key. // As such, we continuously generate seeds through re-hashing until one works. let mut sk = loop { @@ -116,6 +120,10 @@ impl Keychain { sk.set_compress_public(true); self.microblocks_secret_keys.push(sk.clone()); + debug!("Microblock keypair rotated"; + "burn_block_height" => %burn_block_height, + "pubkey_hash" => %Hash160::from_node_public_key(&StacksPublicKey::from_private(&sk)).to_string(),); + sk } diff --git a/testnet/stacks-node/src/neon_node.rs b/testnet/stacks-node/src/neon_node.rs index 595ba4d373e..82fda5c262f 100644 --- a/testnet/stacks-node/src/neon_node.rs +++ b/testnet/stacks-node/src/neon_node.rs @@ -1033,7 +1033,20 @@ impl InitializedNeonNode { // Generates a new secret key for signing the trail of microblocks // of the upcoming tenure. - let microblock_secret_key = keychain.rotate_microblock_keypair(); + let microblock_secret_key = if attempt > 1 { + match keychain.get_microblock_key() { + Some(k) => k, + None => { + error!( + "Failed to obtain microblock key for mining attempt"; + "attempt" => %attempt + ); + return None; + } + } + } else { + keychain.rotate_microblock_keypair(burn_block.block_height) + }; let mblock_pubkey_hash = Hash160::from_node_public_key(&StacksPublicKey::from_private(µblock_secret_key)); diff --git a/testnet/stacks-node/src/node.rs b/testnet/stacks-node/src/node.rs index 4df02d06fc9..65e2db2e0c3 100644 --- a/testnet/stacks-node/src/node.rs +++ b/testnet/stacks-node/src/node.rs @@ -475,7 +475,9 @@ impl Node { // Generates a new secret key for signing the trail of microblocks // of the upcoming tenure. - let microblock_secret_key = self.keychain.rotate_microblock_keypair(); + let microblock_secret_key = self + .keychain + .rotate_microblock_keypair(block_to_build_upon.block_snapshot.block_height); // Get the stack's chain tip let chain_tip = match self.bootstraping_chain { diff --git a/testnet/stacks-node/src/tests/mempool.rs b/testnet/stacks-node/src/tests/mempool.rs index e3d4a940831..dc7740c9443 100644 --- a/testnet/stacks-node/src/tests/mempool.rs +++ b/testnet/stacks-node/src/tests/mempool.rs @@ -637,8 +637,8 @@ fn mempool_setup_chainstate() { conf.node.seed = vec![0x00]; let mut keychain = Keychain::default(conf.node.seed.clone()); - for _i in 0..4 { - let microblock_secret_key = keychain.rotate_microblock_keypair(); + for i in 0..4 { + let microblock_secret_key = keychain.rotate_microblock_keypair(1 + i); let mut microblock_pubkey = Secp256k1PublicKey::from_private(µblock_secret_key); microblock_pubkey.set_compressed(true); diff --git a/testnet/stacks-node/src/tests/neon_integrations.rs b/testnet/stacks-node/src/tests/neon_integrations.rs index dd428b781f4..55764d94a5e 100644 --- a/testnet/stacks-node/src/tests/neon_integrations.rs +++ b/testnet/stacks-node/src/tests/neon_integrations.rs @@ -197,8 +197,9 @@ fn find_microblock_privkey( max_tries: u64, ) -> Option { let mut keychain = Keychain::default(conf.node.seed.clone()); - for _ in 0..max_tries { - let privk = keychain.rotate_microblock_keypair(); + for ix in 0..max_tries { + // the first rotation occurs at 203. + let privk = keychain.rotate_microblock_keypair(203 + ix); let pubkh = Hash160::from_node_public_key(&StacksPublicKey::from_private(&privk)); if pubkh == *pubkey_hash { return Some(privk);