fix: verify that the canonical tip matches the miner tip, and only mine microblocks if not. They may not match if the miner creates an invalid block for some reason (e.g. due to a bug)

This commit is contained in:
Jude Nelson
2022-11-16 15:25:07 -05:00
parent 86c0913c5c
commit 8b1fa1722f

View File

@@ -1632,8 +1632,16 @@ impl BlockMinerThread {
let microblock_private_key = self.make_microblock_private_key(
&parent_block_info.stacks_parent_header.index_block_hash(),
);
let mblock_pubkey_hash =
Hash160::from_node_public_key(&StacksPublicKey::from_private(&microblock_private_key));
let mblock_pubkey_hash = {
let mut pubkh = Hash160::from_node_public_key(&StacksPublicKey::from_private(&microblock_private_key));
if cfg!(test) {
if let Ok(mblock_pubkey_hash_str) = std::env::var("STACKS_MICROBLOCK_PUBKEY_HASH") {
debug!("Fault injection: set microblock public key hash to {}", &mblock_pubkey_hash_str);
pubkh = Hash160::from_hex(&mblock_pubkey_hash_str).expect(&format!("Malformed fault-injected microblock public key hash '{}'", &mblock_pubkey_hash_str));
}
}
pubkh
};
// create our coinbase
let coinbase_tx = self.inner_generate_coinbase_tx(parent_block_info.coinbase_nonce);
@@ -2185,10 +2193,10 @@ impl RelayerThread {
/// Return Err(..) if we couldn't reach the chains coordiantor thread
fn process_new_block(&self) -> Result<bool, Error> {
// process the block
let stacks_blocks_processed = self.globals.coord_comms.get_stacks_blocks_processed();
if !self.globals.coord_comms.announce_new_stacks_block() {
return Err(Error::CoordinatorClosed);
}
let stacks_blocks_processed = self.globals.coord_comms.get_stacks_blocks_processed();
if !self
.globals
.coord_comms
@@ -2471,21 +2479,35 @@ impl RelayerThread {
self.last_tenure_consensus_hash = Some(consensus_hash);
}
if let Some(miner_tip) = miner_tip.as_ref() {
debug!(
"Relayer: Microblock miner tip is now {}/{} ({})",
miner_tip.consensus_hash,
miner_tip.block_hash,
StacksBlockHeader::make_index_block_hash(
&miner_tip.consensus_hash,
&miner_tip.block_hash
)
);
self.with_chainstate(|relayer_thread, sortdb, chainstate, _mempool| {
Relayer::refresh_unconfirmed(chainstate, sortdb);
relayer_thread.globals.send_unconfirmed_txs(chainstate);
if let Some(miner_tip) = miner_tip.take() {
// sanity check -- is this also the canonical tip?
let (stacks_tip_consensus_hash, stacks_tip_block_hash) = self.with_chainstate(|_relayer_thread, sortdb, _chainstate, _| {
SortitionDB::get_canonical_stacks_chain_tip_hash(sortdb.conn())
.expect("FATAL: failed to query sortition DB for canonical stacks chain tip hashes")
});
if miner_tip.consensus_hash != stacks_tip_consensus_hash || miner_tip.block_hash != stacks_tip_block_hash {
debug!("Relayer: miner tip {}/{} is NOT canonical ({}/{})", &miner_tip.consensus_hash, &miner_tip.block_hash, &stacks_tip_consensus_hash, &stacks_tip_block_hash);
self.miner_tip = None;
}
else {
debug!(
"Relayer: Microblock miner tip is now {}/{} ({})",
miner_tip.consensus_hash,
miner_tip.block_hash,
StacksBlockHeader::make_index_block_hash(
&miner_tip.consensus_hash,
&miner_tip.block_hash
)
);
self.with_chainstate(|relayer_thread, sortdb, chainstate, _mempool| {
Relayer::refresh_unconfirmed(chainstate, sortdb);
relayer_thread.globals.send_unconfirmed_txs(chainstate);
});
self.miner_tip = Some(miner_tip);
}
}
// update state for microblock mining