Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/6985-shadow-block-parent.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Block-commits were unable to be validated if the PoX anchor block happened to be a shadow block.
2 changes: 2 additions & 0 deletions stacks-node/src/burnchains/bitcoin_regtest_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2586,6 +2586,7 @@ mod tests {
vtxindex: 0,
block_height: 2212,
burn_header_hash: BurnchainHeaderHash([0x01; 32]),
descends_from_anchor_block: true,
}
}

Expand Down Expand Up @@ -2872,6 +2873,7 @@ mod tests {
vtxindex: 0,
block_height: 2212,
burn_header_hash: BurnchainHeaderHash([0x01; 32]),
descends_from_anchor_block: true,
};

assert_eq!(to_hex(&commit_op.serialize_to_vec()), "5be88c3d30cb59a142f83de3b27f897a43bbb0f13316911bb98a3229973dae32afd5b9f21bc1f40f24e2c101ecd13c55b8619e5e03dad81de2c62a1cc1d8c1b375000008a300010000059800015a".to_string());
Expand Down
1 change: 1 addition & 0 deletions stacks-node/src/burnchains/mocknet_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ impl BurnchainController for MocknetController {
BURN_BLOCK_MINED_AT_MODULUS - 1
} as u8,
burn_header_hash: next_block_header.block_hash.clone(),
descends_from_anchor_block: true,
})
}
BlockstackOperationType::PreStx(payload) => {
Expand Down
1 change: 1 addition & 0 deletions stacks-node/src/nakamoto_node/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,7 @@ impl RelayerThread {
txid: Txid([0u8; 32]),
block_height: 0,
burn_header_hash: BurnchainHeaderHash::zero(),
descends_from_anchor_block: true,
};

if std::env::var("FAULT_INJECTION_BLOCK_COMMIT_VTXINDEX_SENTINEL") == Ok("1".to_string()) {
Expand Down
2 changes: 2 additions & 0 deletions stacks-node/src/neon_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,8 @@ impl BlockMinerThread {
burn_header_hash: BurnchainHeaderHash::zero(),
burn_parent_modulus,
commit_outs,
// unused
descends_from_anchor_block: true,
})
}

Expand Down
1 change: 1 addition & 0 deletions stacks-node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@ impl Node {
block_height: 0,
burn_header_hash: BurnchainHeaderHash::zero(),
burn_parent_modulus,
descends_from_anchor_block: true,
})
}

Expand Down
1 change: 1 addition & 0 deletions stacks-node/src/tests/epoch_205.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ fn transition_empty_blocks() {
burn_header_hash: BurnchainHeaderHash::zero(),
burn_parent_modulus,
commit_outs,
descends_from_anchor_block: true,
});
let mut op_signer = keychain.generate_op_signer();
let res =
Expand Down
1 change: 1 addition & 0 deletions stacks-node/src/tests/epoch_21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ fn transition_empty_blocks() {
burn_header_hash: BurnchainHeaderHash::zero(),
burn_parent_modulus,
commit_outs,
descends_from_anchor_block: true,
});
let mut op_signer = keychain.generate_op_signer();
let res =
Expand Down
26 changes: 26 additions & 0 deletions stacks-node/src/tests/nakamoto_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10695,6 +10695,32 @@ fn test_shadow_recovery() {
assert!(has_epoch_3_recovery);
assert!(has_shadow_blocks);
assert!(has_epoch_3_failure);

// make sure we can still mine, even across reward cycles
for _i in 0..(burnchain.pox_constants.reward_cycle_length + 1) {
let chain_info = get_chain_info(&naka_conf);
let target_burn_height = chain_info.burn_block_height + 1;
let target_stacks_height = chain_info.stacks_tip_height + 1;
btc_regtest_controller.build_next_block(1);
wait_for(30, || {
let chain_info = get_chain_info(&naka_conf);
if chain_info.burn_block_height >= target_burn_height
&& chain_info.stacks_tip_height >= target_stacks_height
{
return Ok(true);
}
Ok(false)
})
.unwrap();

// must have gotten a block-commit
let burnchain = naka_conf.get_burnchain();
let sortdb = burnchain.open_sortition_db(true).unwrap();
let tip = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()).unwrap();
let ops =
SortitionDB::get_block_commits_by_block(sortdb.conn(), &tip.sortition_id).unwrap();
assert!(!ops.is_empty());
}
}

#[test]
Expand Down
4 changes: 4 additions & 0 deletions stackslib/src/burnchains/tests/burnchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ fn test_process_block_ops() {
block_height: 124,
burn_parent_modulus: (123 % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: block_124_hash_initial.clone(),
descends_from_anchor_block: false,
};

let block_commit_2 = LeaderBlockCommitOp {
Expand Down Expand Up @@ -218,6 +219,7 @@ fn test_process_block_ops() {
block_height: 124,
burn_parent_modulus: (123 % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: block_124_hash_initial.clone(),
descends_from_anchor_block: false,
};

let block_commit_3 = LeaderBlockCommitOp {
Expand Down Expand Up @@ -257,6 +259,7 @@ fn test_process_block_ops() {
block_height: 124,
burn_parent_modulus: (123 % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: block_124_hash_initial.clone(),
descends_from_anchor_block: false,
};

let block_ops_121: Vec<BlockstackOperationType> =
Expand Down Expand Up @@ -800,6 +803,7 @@ fn test_burn_snapshot_sequence() {
burn_parent_modulus: ((first_block_height + (i as u64))
% BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: burn_block_hash.clone(),
descends_from_anchor_block: false,
};

block_ops.push(BlockstackOperationType::LeaderBlockCommit(
Expand Down
1 change: 1 addition & 0 deletions stackslib/src/burnchains/tests/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ pub fn make_simple_block_commit(
block_height,
burn_parent_modulus: ((block_height - 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: burn_header.block_hash.clone(),
descends_from_anchor_block: true,
};

if burnchain.is_in_prepare_phase(block_height) {
Expand Down
1 change: 1 addition & 0 deletions stackslib/src/chainstate/burn/db/processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ mod tests {
burn_parent_modulus: (101 % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x03; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

let mut burnchain = Burnchain::default_unittest(100, &first_burn_hash);
Expand Down
82 changes: 79 additions & 3 deletions stackslib/src/chainstate/burn/db/sortdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ impl FromRow<LeaderBlockCommitOp> for LeaderBlockCommitOp {
.map_err(db_error::SerializationError)?
.unwrap_or_default();

let descends_from_anchor_block_opt: Option<bool> = row.get("descends_from_anchor_block")?;
let block_commit = LeaderBlockCommitOp {
block_header_hash,
new_seed,
Expand All @@ -294,6 +295,7 @@ impl FromRow<LeaderBlockCommitOp> for LeaderBlockCommitOp {
block_height,
burn_header_hash,
treatment: punished,
descends_from_anchor_block: descends_from_anchor_block_opt.unwrap_or(false),
};
Ok(block_commit)
}
Expand Down Expand Up @@ -485,7 +487,7 @@ impl FromRow<StacksEpoch> for StacksEpoch {
}
}

pub const SORTITION_DB_VERSION: u32 = 11;
pub const SORTITION_DB_VERSION: u32 = 12;

const SORTITION_DB_INITIAL_SCHEMA: &[&str] = &[
r#"
Expand Down Expand Up @@ -741,6 +743,9 @@ static SORTITION_DB_SCHEMA_11: &[&str] = &[r#"
);
"#];

static SORTITION_DB_SCHEMA_12: &[&str] =
&[r#"ALTER TABLE block_commits ADD descends_from_anchor_block BOOLEAN DEFAULT NULL;"#];
Comment thread
brice-stacks marked this conversation as resolved.

const LAST_SORTITION_DB_INDEX: &str =
"stacks_chain_tips_by_burn_view_by_sortition_id_and_block_height";
const SORTITION_DB_INDEXES: &[&str] = &[
Expand Down Expand Up @@ -1072,6 +1077,13 @@ pub trait SortitionHandle {
Ok(Some(StacksBlockId::new(&ch, &bhh)))
}

/// Get an ancestral sortition ID
fn get_ancestor_sort_id(
&mut self,
block_height: u64,
tip: &SortitionId,
) -> Result<Option<SortitionId>, db_error>;

/// Check if the descendancy cache has an entry for whether or not the winning block in `key.0`
/// descends from `key.1`
///
Expand Down Expand Up @@ -1210,6 +1222,29 @@ pub trait SortitionHandle {
);
return Ok(false);
}

/// Get a parent block commit at a specific location in the burn chain on a particular fork.
/// Returns None if there is no block commit at this location.
fn get_block_commit_parent(
&mut self,
block_height: u64,
vtxindex: u32,
tip: &SortitionId,
) -> Result<Option<LeaderBlockCommitOp>, db_error> {
if block_height >= BLOCK_HEIGHT_MAX {
return Err(db_error::BlockHeightOutOfRange);
}
let Some(ancestor_id) = self.get_ancestor_sort_id(block_height, tip)? else {
return Ok(None);
};

SortitionDB::get_block_commit_of_sortition(
self.sqlite(),
&ancestor_id,
block_height,
vtxindex,
)
}
}

impl<'a> SortitionHandleTx<'a> {
Expand Down Expand Up @@ -1578,6 +1613,14 @@ impl SortitionHandle for SortitionHandleTx<'_> {
self.context.chain_tip.clone()
}

fn get_ancestor_sort_id(
&mut self,
block_height: u64,
tip: &SortitionId,
) -> Result<Option<SortitionId>, db_error> {
get_ancestor_sort_id_tx(self, block_height, tip)
}

fn get_nakamoto_tip(&self) -> Result<Option<(ConsensusHash, BlockHeaderHash, u64)>, db_error> {
let sn = SortitionDB::get_block_snapshot(self.sqlite(), &self.context.chain_tip)?
.ok_or(db_error::NotFoundError)?;
Expand Down Expand Up @@ -1609,6 +1652,14 @@ impl SortitionHandle for SortitionHandleConn<'_> {
self.context.chain_tip.clone()
}

fn get_ancestor_sort_id(
&mut self,
block_height: u64,
tip: &SortitionId,
) -> Result<Option<SortitionId>, db_error> {
get_ancestor_sort_id(self, block_height, tip)
}

fn get_nakamoto_tip(&self) -> Result<Option<(ConsensusHash, BlockHeaderHash, u64)>, db_error> {
let sn = SortitionDB::get_block_snapshot(self.sqlite(), &self.context.chain_tip)?
.ok_or(db_error::NotFoundError)?;
Expand Down Expand Up @@ -2925,6 +2976,7 @@ impl SortitionDB {
SortitionDB::apply_schema_9(&db_tx, epochs_ref)?;
SortitionDB::apply_schema_10(&db_tx)?;
SortitionDB::apply_schema_11(&db_tx)?;
SortitionDB::apply_schema_12(&db_tx)?;
db_tx.commit()?;

self.add_indexes()?;
Expand Down Expand Up @@ -3434,6 +3486,19 @@ impl SortitionDB {
Ok(())
}

fn apply_schema_12(tx: &DBTx) -> Result<(), db_error> {
for sql_exec in SORTITION_DB_SCHEMA_12 {
tx.execute_batch(sql_exec)?;
}

tx.execute(
"INSERT OR REPLACE INTO db_config (version) VALUES (?1)",
&["12"],
)?;

Ok(())
}

fn check_schema_version_or_error(&mut self) -> Result<(), db_error> {
match SortitionDB::get_schema_version(self.conn()) {
Ok(Some(version)) => {
Expand Down Expand Up @@ -3503,6 +3568,10 @@ impl SortitionDB {
let tx = self.tx_begin()?;
SortitionDB::apply_schema_11(tx.deref())?;
tx.commit()?;
} else if version == 11 {
let tx = self.tx_begin()?;
SortitionDB::apply_schema_12(tx.deref())?;
tx.commit()?;
} else if version == SORTITION_DB_VERSION {
// this transaction is almost never needed
let validated_epochs = StacksEpoch::validate_epochs(epochs);
Expand Down Expand Up @@ -5858,10 +5927,11 @@ impl SortitionHandleTx<'_> {
apparent_sender_str,
block_commit.burn_parent_modulus,
serde_json::to_string(&block_commit.treatment).unwrap(),
block_commit.descends_from_anchor_block
];

self.execute("INSERT INTO block_commits (txid, vtxindex, block_height, burn_header_hash, block_header_hash, new_seed, parent_block_ptr, parent_vtxindex, key_block_ptr, key_vtxindex, memo, burn_fee, input, sortition_id, commit_outs, sunset_burn, apparent_sender, burn_parent_modulus, punished) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19)", args)?;
self.execute("INSERT INTO block_commits (txid, vtxindex, block_height, burn_header_hash, block_header_hash, new_seed, parent_block_ptr, parent_vtxindex, key_block_ptr, key_vtxindex, memo, burn_fee, input, sortition_id, commit_outs, sunset_burn, apparent_sender, burn_parent_modulus, punished, descends_from_anchor_block) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20)", args)?;

let parent_args = params![sort_id, block_commit.txid, parent_sortition_id];

Expand Down Expand Up @@ -7409,6 +7479,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x03; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

let mut db = SortitionDB::connect_test(block_height, &first_burn_hash).unwrap();
Expand Down Expand Up @@ -8124,6 +8195,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x03; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

let mut db = SortitionDB::connect_test(block_height, &first_burn_hash).unwrap();
Expand Down Expand Up @@ -10371,6 +10443,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 1) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x03; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

// descends from genesis
Expand Down Expand Up @@ -10414,6 +10487,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 2) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x04; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

// descends from block_commit_1
Expand Down Expand Up @@ -10457,6 +10531,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 3) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x05; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

// descends from genesis_block_commit
Expand Down Expand Up @@ -10500,6 +10575,7 @@ pub mod tests {
burn_parent_modulus: ((block_height + 4) % BURN_BLOCK_MINED_AT_MODULUS) as u8,
burn_header_hash: BurnchainHeaderHash([0x06; 32]),
treatment: vec![],
descends_from_anchor_block: false,
};

let mut db = SortitionDB::connect_test(block_height, &first_burn_hash).unwrap();
Expand Down
4 changes: 4 additions & 0 deletions stackslib/src/chainstate/burn/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ mod tests {
BURN_BLOCK_MINED_AT_MODULUS as u8 - 1
},
burn_header_hash: BurnchainHeaderHash([0; 32]),
descends_from_anchor_block: false,
}
}

Expand Down Expand Up @@ -912,6 +913,7 @@ mod tests {
"0000000000000000000000000000000000000000000000000000000000000004",
)
.unwrap(),
descends_from_anchor_block: false,
};

let block_commit_2 = LeaderBlockCommitOp {
Expand Down Expand Up @@ -958,6 +960,7 @@ mod tests {
"0000000000000000000000000000000000000000000000000000000000000004",
)
.unwrap(),
descends_from_anchor_block: false,
};

let block_commit_3 = LeaderBlockCommitOp {
Expand Down Expand Up @@ -1004,6 +1007,7 @@ mod tests {
"0000000000000000000000000000000000000000000000000000000000000004",
)
.unwrap(),
descends_from_anchor_block: false,
};

/*
Expand Down
Loading
Loading