Skip to content

Commit

Permalink
Merge pull request #2052 from blockstack/fix/1934
Browse files Browse the repository at this point in the history
Fix 1934: mix burn block height into microblock pubkey
  • Loading branch information
kantai authored Nov 11, 2020
2 parents 0b96be3 + bcc602b commit 151e06e
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/vm/docs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
};
Expand Down
18 changes: 13 additions & 5 deletions testnet/stacks-node/src/keychain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down
15 changes: 14 additions & 1 deletion testnet/stacks-node/src/neon_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(&microblock_secret_key));

Expand Down
4 changes: 3 additions & 1 deletion testnet/stacks-node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions testnet/stacks-node/src/tests/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(&microblock_secret_key);
microblock_pubkey.set_compressed(true);
Expand Down
5 changes: 3 additions & 2 deletions testnet/stacks-node/src/tests/neon_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,9 @@ fn find_microblock_privkey(
max_tries: u64,
) -> Option<StacksPrivateKey> {
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);
Expand Down

0 comments on commit 151e06e

Please sign in to comment.