Skip to content

Commit 34d658a

Browse files
committed
Merge branch 'develop' into fix/5285
2 parents c60b569 + 20d5137 commit 34d658a

39 files changed

+741
-546
lines changed

stacks-common/src/types/mod.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cmp::Ordering;
22
use std::fmt;
3+
use std::ops::{Deref, DerefMut, Index, IndexMut};
34

45
#[cfg(feature = "canonical")]
56
pub mod sqlite;
@@ -475,3 +476,83 @@ impl<L: PartialEq + Eq> Ord for StacksEpoch<L> {
475476
self.epoch_id.cmp(&other.epoch_id)
476477
}
477478
}
479+
480+
/// A wrapper for holding a list of Epochs, indexable by StacksEpochId
481+
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq)]
482+
pub struct EpochList<L: Clone>(Vec<StacksEpoch<L>>);
483+
484+
impl<L: Clone> EpochList<L> {
485+
pub fn new(epochs: &[StacksEpoch<L>]) -> EpochList<L> {
486+
EpochList(epochs.to_vec())
487+
}
488+
489+
pub fn get(&self, index: StacksEpochId) -> Option<&StacksEpoch<L>> {
490+
self.0.get(StacksEpoch::find_epoch_by_id(&self.0, index)?)
491+
}
492+
493+
pub fn get_mut(&mut self, index: StacksEpochId) -> Option<&mut StacksEpoch<L>> {
494+
let index = StacksEpoch::find_epoch_by_id(&self.0, index)?;
495+
self.0.get_mut(index)
496+
}
497+
498+
/// Truncates the list after the given epoch id
499+
pub fn truncate_after(&mut self, epoch_id: StacksEpochId) {
500+
if let Some(index) = StacksEpoch::find_epoch_by_id(&self.0, epoch_id) {
501+
self.0.truncate(index + 1);
502+
}
503+
}
504+
505+
/// Determine which epoch, if any, a given burnchain height falls into.
506+
pub fn epoch_id_at_height(&self, height: u64) -> Option<StacksEpochId> {
507+
StacksEpoch::find_epoch(self, height).map(|idx| self.0[idx].epoch_id)
508+
}
509+
510+
/// Determine which epoch, if any, a given burnchain height falls into.
511+
pub fn epoch_at_height(&self, height: u64) -> Option<StacksEpoch<L>> {
512+
StacksEpoch::find_epoch(self, height).map(|idx| self.0[idx].clone())
513+
}
514+
515+
/// Pushes a new `StacksEpoch` to the end of the list
516+
pub fn push(&mut self, epoch: StacksEpoch<L>) {
517+
if let Some(last) = self.0.last() {
518+
assert!(
519+
epoch.start_height == last.end_height && epoch.epoch_id > last.epoch_id,
520+
"Epochs must be pushed in order"
521+
);
522+
}
523+
self.0.push(epoch);
524+
}
525+
526+
pub fn to_vec(&self) -> Vec<StacksEpoch<L>> {
527+
self.0.clone()
528+
}
529+
}
530+
531+
impl<L: Clone> Index<StacksEpochId> for EpochList<L> {
532+
type Output = StacksEpoch<L>;
533+
fn index(&self, index: StacksEpochId) -> &StacksEpoch<L> {
534+
self.get(index)
535+
.expect("Invalid StacksEpochId: could not find corresponding epoch")
536+
}
537+
}
538+
539+
impl<L: Clone> IndexMut<StacksEpochId> for EpochList<L> {
540+
fn index_mut(&mut self, index: StacksEpochId) -> &mut StacksEpoch<L> {
541+
self.get_mut(index)
542+
.expect("Invalid StacksEpochId: could not find corresponding epoch")
543+
}
544+
}
545+
546+
impl<L: Clone> Deref for EpochList<L> {
547+
type Target = [StacksEpoch<L>];
548+
549+
fn deref(&self) -> &Self::Target {
550+
&self.0
551+
}
552+
}
553+
554+
impl<L: Clone> DerefMut for EpochList<L> {
555+
fn deref_mut(&mut self) -> &mut Self::Target {
556+
&mut self.0
557+
}
558+
}

stacks-signer/src/v0/signer.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader};
2121
use blockstack_lib::net::api::postblock_proposal::{
2222
BlockValidateOk, BlockValidateReject, BlockValidateResponse,
2323
};
24+
use blockstack_lib::util_lib::db::Error as DBError;
2425
use clarity::types::chainstate::StacksPrivateKey;
2526
use clarity::types::{PrivateKey, StacksEpochId};
2627
use clarity::util::hash::MerkleHashFunc;
@@ -496,7 +497,7 @@ impl Signer {
496497
// Do not store KNOWN invalid blocks as this could DOS the signer. We only store blocks that are valid or unknown.
497498
self.signer_db
498499
.insert_block(&block_info)
499-
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
500+
.unwrap_or_else(|e| self.handle_insert_block_error(e));
500501
}
501502
}
502503

@@ -568,7 +569,7 @@ impl Signer {
568569

569570
self.signer_db
570571
.insert_block(&block_info)
571-
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
572+
.unwrap_or_else(|e| self.handle_insert_block_error(e));
572573
let accepted = BlockAccepted::new(block_info.signer_signature_hash(), signature);
573574
// have to save the signature _after_ the block info
574575
self.handle_block_signature(stacks_client, &accepted);
@@ -626,7 +627,7 @@ impl Signer {
626627
);
627628
self.signer_db
628629
.insert_block(&block_info)
629-
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
630+
.unwrap_or_else(|e| self.handle_insert_block_error(e));
630631
self.handle_block_rejection(&block_rejection);
631632
Some(BlockResponse::Rejected(block_rejection))
632633
}
@@ -739,7 +740,7 @@ impl Signer {
739740
}
740741
self.signer_db
741742
.insert_block(&block_info)
742-
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
743+
.unwrap_or_else(|e| self.handle_insert_block_error(e));
743744
}
744745

745746
/// Compute the signing weight, given a list of signatures
@@ -1095,7 +1096,7 @@ impl Signer {
10951096
// in case this is the first time we saw this block. Safe to do since this is testing case only.
10961097
self.signer_db
10971098
.insert_block(block_info)
1098-
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
1099+
.unwrap_or_else(|e| self.handle_insert_block_error(e));
10991100
Some(BlockResponse::rejected(
11001101
block_proposal.block.header.signer_signature_hash(),
11011102
RejectCode::TestingDirective,
@@ -1119,4 +1120,10 @@ impl Signer {
11191120
warn!("{self}: Failed to send mock signature to stacker-db: {e:?}",);
11201121
}
11211122
}
1123+
1124+
/// Helper for logging insert_block error
1125+
fn handle_insert_block_error(&self, e: DBError) {
1126+
error!("{self}: Failed to insert block into signer-db: {e:?}");
1127+
panic!("{self} Failed to write block to signerdb: {e}");
1128+
}
11221129
}

stackslib/src/burnchains/bitcoin/indexer.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::burnchains::{
4545
Burnchain, BurnchainBlockHeader, Error as burnchain_error, MagicBytes, BLOCKSTACK_MAGIC_MAINNET,
4646
};
4747
use crate::core::{
48-
StacksEpoch, StacksEpochExtension, STACKS_EPOCHS_MAINNET, STACKS_EPOCHS_REGTEST,
48+
EpochList, StacksEpoch, StacksEpochExtension, STACKS_EPOCHS_MAINNET, STACKS_EPOCHS_REGTEST,
4949
STACKS_EPOCHS_TESTNET,
5050
};
5151
use crate::util_lib::db::Error as DBError;
@@ -91,11 +91,11 @@ impl TryFrom<u32> for BitcoinNetworkType {
9191
/// Get the default epochs definitions for the given BitcoinNetworkType.
9292
/// Should *not* be used except by the BitcoinIndexer when no epochs vector
9393
/// was specified.
94-
pub fn get_bitcoin_stacks_epochs(network_id: BitcoinNetworkType) -> Vec<StacksEpoch> {
94+
pub fn get_bitcoin_stacks_epochs(network_id: BitcoinNetworkType) -> EpochList {
9595
match network_id {
96-
BitcoinNetworkType::Mainnet => STACKS_EPOCHS_MAINNET.to_vec(),
97-
BitcoinNetworkType::Testnet => STACKS_EPOCHS_TESTNET.to_vec(),
98-
BitcoinNetworkType::Regtest => STACKS_EPOCHS_REGTEST.to_vec(),
96+
BitcoinNetworkType::Mainnet => (*STACKS_EPOCHS_MAINNET).clone(),
97+
BitcoinNetworkType::Testnet => (*STACKS_EPOCHS_TESTNET).clone(),
98+
BitcoinNetworkType::Regtest => (*STACKS_EPOCHS_REGTEST).clone(),
9999
}
100100
}
101101

@@ -112,7 +112,7 @@ pub struct BitcoinIndexerConfig {
112112
pub spv_headers_path: String,
113113
pub first_block: u64,
114114
pub magic_bytes: MagicBytes,
115-
pub epochs: Option<Vec<StacksEpoch>>,
115+
pub epochs: Option<EpochList>,
116116
}
117117

118118
#[derive(Debug)]
@@ -1041,7 +1041,7 @@ impl BurnchainIndexer for BitcoinIndexer {
10411041
/// 2) Use hard-coded static values, otherwise.
10421042
///
10431043
/// It is an error (panic) to set custom epochs if running on `Mainnet`.
1044-
fn get_stacks_epochs(&self) -> Vec<StacksEpoch> {
1044+
fn get_stacks_epochs(&self) -> EpochList {
10451045
StacksEpoch::get_epochs(self.runtime.network_id, self.config.epochs.as_ref())
10461046
}
10471047

stackslib/src/burnchains/burnchain.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use stacks_common::util::hash::to_hex;
2929
use stacks_common::util::vrf::VRFPublicKey;
3030
use stacks_common::util::{get_epoch_time_ms, get_epoch_time_secs, log, sleep_ms};
3131

32+
use super::EpochList;
3233
use crate::burnchains::affirmation::update_pox_affirmation_maps;
3334
use crate::burnchains::bitcoin::address::{
3435
to_c32_version_byte, BitcoinAddress, LegacyBitcoinAddressType,
@@ -722,7 +723,7 @@ impl Burnchain {
722723
readwrite: bool,
723724
first_block_header_hash: BurnchainHeaderHash,
724725
first_block_header_timestamp: u64,
725-
epochs: Vec<StacksEpoch>,
726+
epochs: EpochList,
726727
) -> Result<(SortitionDB, BurnchainDB), burnchain_error> {
727728
Burnchain::setup_chainstate_dirs(&self.working_dir)?;
728729

stackslib/src/burnchains/indexer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub trait BurnchainIndexer {
6262
fn get_first_block_height(&self) -> u64;
6363
fn get_first_block_header_hash(&self) -> Result<BurnchainHeaderHash, burnchain_error>;
6464
fn get_first_block_header_timestamp(&self) -> Result<u64, burnchain_error>;
65-
fn get_stacks_epochs(&self) -> Vec<StacksEpoch>;
65+
fn get_stacks_epochs(&self) -> EpochList;
6666

6767
fn get_headers_path(&self) -> String;
6868
fn get_headers_height(&self) -> Result<u64, burnchain_error>;

stackslib/src/chainstate/burn/db/sortdb.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2969,9 +2969,9 @@ impl SortitionDB {
29692969
db_tx: &Transaction,
29702970
epochs: &[StacksEpoch],
29712971
) -> Result<(), db_error> {
2972-
let epochs = StacksEpoch::validate_epochs(epochs);
2972+
let epochs: &[StacksEpoch] = &StacksEpoch::validate_epochs(epochs);
29732973
let existing_epochs = Self::get_stacks_epochs(db_tx)?;
2974-
if existing_epochs == epochs {
2974+
if &existing_epochs == epochs {
29752975
return Ok(());
29762976
}
29772977

@@ -3482,9 +3482,10 @@ impl SortitionDB {
34823482
tx.commit()?;
34833483
} else if version == expected_version {
34843484
// this transaction is almost never needed
3485-
let validated_epochs = StacksEpoch::validate_epochs(epochs);
3485+
let validated_epochs: &[StacksEpoch] =
3486+
&StacksEpoch::validate_epochs(epochs);
34863487
let existing_epochs = Self::get_stacks_epochs(self.conn())?;
3487-
if existing_epochs == validated_epochs {
3488+
if &existing_epochs == validated_epochs {
34883489
return Ok(());
34893490
}
34903491

@@ -6636,7 +6637,7 @@ pub mod tests {
66366637
pub fn connect_test_with_epochs(
66376638
first_block_height: u64,
66386639
first_burn_hash: &BurnchainHeaderHash,
6639-
epochs: Vec<StacksEpoch>,
6640+
epochs: EpochList,
66406641
) -> Result<SortitionDB, db_error> {
66416642
let mut rng = rand::thread_rng();
66426643
let mut buf = [0u8; 32];
@@ -10930,10 +10931,9 @@ pub mod tests {
1093010931

1093110932
fs::create_dir_all(path_root).unwrap();
1093210933

10933-
let mut bad_epochs = STACKS_EPOCHS_MAINNET.to_vec();
10934-
let idx = bad_epochs.len() - 2;
10935-
bad_epochs[idx].end_height += 1;
10936-
bad_epochs[idx + 1].start_height += 1;
10934+
let mut bad_epochs = (*STACKS_EPOCHS_MAINNET).clone();
10935+
bad_epochs[StacksEpochId::Epoch25].end_height += 1;
10936+
bad_epochs[StacksEpochId::Epoch30].start_height += 1;
1093710937

1093810938
let sortdb = SortitionDB::connect(
1093910939
&format!("{}/sortdb.sqlite", &path_root),
@@ -10948,14 +10948,14 @@ pub mod tests {
1094810948
.unwrap();
1094910949

1095010950
let db_epochs = SortitionDB::get_stacks_epochs(sortdb.conn()).unwrap();
10951-
assert_eq!(db_epochs, bad_epochs);
10951+
assert_eq!(db_epochs, bad_epochs.to_vec());
1095210952

1095310953
let fixed_sortdb = SortitionDB::connect(
1095410954
&format!("{}/sortdb.sqlite", &path_root),
1095510955
0,
1095610956
&BurnchainHeaderHash([0x00; 32]),
1095710957
0,
10958-
&STACKS_EPOCHS_MAINNET.to_vec(),
10958+
&STACKS_EPOCHS_MAINNET,
1095910959
PoxConstants::mainnet_default(),
1096010960
None,
1096110961
true,

stackslib/src/chainstate/coordinator/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ pub fn setup_states_with_epochs(
290290
pox_consts: Option<PoxConstants>,
291291
initial_balances: Option<Vec<(PrincipalData, u64)>>,
292292
stacks_epoch_id: StacksEpochId,
293-
epochs_opt: Option<Vec<StacksEpoch>>,
293+
epochs_opt: Option<EpochList>,
294294
) {
295295
let mut burn_block = None;
296296
let mut others = vec![];

stackslib/src/chainstate/stacks/boot/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,7 @@ pub mod test {
16401640
pub fn instantiate_pox_peer_with_epoch<'a>(
16411641
burnchain: &Burnchain,
16421642
test_name: &str,
1643-
epochs: Option<Vec<StacksEpoch>>,
1643+
epochs: Option<EpochList>,
16441644
observer: Option<&'a TestEventObserver>,
16451645
) -> (TestPeer<'a>, Vec<StacksPrivateKey>) {
16461646
let mut peer_config = TestPeerConfig::new(test_name, 0, 0);

0 commit comments

Comments
 (0)