Skip to content

Commit d36c548

Browse files
committed
Merge branch 'develop' into feat/sip-029
2 parents 7568bf5 + 20d5137 commit d36c548

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1115
-559
lines changed

stacks-common/src/types/mod.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use std::cell::LazyCell;
1818
use std::cmp::Ordering;
1919
use std::fmt;
20+
use std::ops::{Deref, DerefMut, Index, IndexMut};
2021

2122
#[cfg(feature = "canonical")]
2223
pub mod sqlite;
@@ -762,3 +763,83 @@ impl<L: PartialEq + Eq> Ord for StacksEpoch<L> {
762763
self.epoch_id.cmp(&other.epoch_id)
763764
}
764765
}
766+
767+
/// A wrapper for holding a list of Epochs, indexable by StacksEpochId
768+
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq)]
769+
pub struct EpochList<L: Clone>(Vec<StacksEpoch<L>>);
770+
771+
impl<L: Clone> EpochList<L> {
772+
pub fn new(epochs: &[StacksEpoch<L>]) -> EpochList<L> {
773+
EpochList(epochs.to_vec())
774+
}
775+
776+
pub fn get(&self, index: StacksEpochId) -> Option<&StacksEpoch<L>> {
777+
self.0.get(StacksEpoch::find_epoch_by_id(&self.0, index)?)
778+
}
779+
780+
pub fn get_mut(&mut self, index: StacksEpochId) -> Option<&mut StacksEpoch<L>> {
781+
let index = StacksEpoch::find_epoch_by_id(&self.0, index)?;
782+
self.0.get_mut(index)
783+
}
784+
785+
/// Truncates the list after the given epoch id
786+
pub fn truncate_after(&mut self, epoch_id: StacksEpochId) {
787+
if let Some(index) = StacksEpoch::find_epoch_by_id(&self.0, epoch_id) {
788+
self.0.truncate(index + 1);
789+
}
790+
}
791+
792+
/// Determine which epoch, if any, a given burnchain height falls into.
793+
pub fn epoch_id_at_height(&self, height: u64) -> Option<StacksEpochId> {
794+
StacksEpoch::find_epoch(self, height).map(|idx| self.0[idx].epoch_id)
795+
}
796+
797+
/// Determine which epoch, if any, a given burnchain height falls into.
798+
pub fn epoch_at_height(&self, height: u64) -> Option<StacksEpoch<L>> {
799+
StacksEpoch::find_epoch(self, height).map(|idx| self.0[idx].clone())
800+
}
801+
802+
/// Pushes a new `StacksEpoch` to the end of the list
803+
pub fn push(&mut self, epoch: StacksEpoch<L>) {
804+
if let Some(last) = self.0.last() {
805+
assert!(
806+
epoch.start_height == last.end_height && epoch.epoch_id > last.epoch_id,
807+
"Epochs must be pushed in order"
808+
);
809+
}
810+
self.0.push(epoch);
811+
}
812+
813+
pub fn to_vec(&self) -> Vec<StacksEpoch<L>> {
814+
self.0.clone()
815+
}
816+
}
817+
818+
impl<L: Clone> Index<StacksEpochId> for EpochList<L> {
819+
type Output = StacksEpoch<L>;
820+
fn index(&self, index: StacksEpochId) -> &StacksEpoch<L> {
821+
self.get(index)
822+
.expect("Invalid StacksEpochId: could not find corresponding epoch")
823+
}
824+
}
825+
826+
impl<L: Clone> IndexMut<StacksEpochId> for EpochList<L> {
827+
fn index_mut(&mut self, index: StacksEpochId) -> &mut StacksEpoch<L> {
828+
self.get_mut(index)
829+
.expect("Invalid StacksEpochId: could not find corresponding epoch")
830+
}
831+
}
832+
833+
impl<L: Clone> Deref for EpochList<L> {
834+
type Target = [StacksEpoch<L>];
835+
836+
fn deref(&self) -> &Self::Target {
837+
&self.0
838+
}
839+
}
840+
841+
impl<L: Clone> DerefMut for EpochList<L> {
842+
fn deref_mut(&mut self) -> &mut Self::Target {
843+
&mut self.0
844+
}
845+
}

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

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

@@ -6639,7 +6640,7 @@ pub mod tests {
66396640
pub fn connect_test_with_epochs(
66406641
first_block_height: u64,
66416642
first_burn_hash: &BurnchainHeaderHash,
6642-
epochs: Vec<StacksEpoch>,
6643+
epochs: EpochList,
66436644
) -> Result<SortitionDB, db_error> {
66446645
let mut rng = rand::thread_rng();
66456646
let mut buf = [0u8; 32];
@@ -10933,10 +10934,9 @@ pub mod tests {
1093310934

1093410935
fs::create_dir_all(path_root).unwrap();
1093510936

10936-
let mut bad_epochs = STACKS_EPOCHS_MAINNET.to_vec();
10937-
let idx = bad_epochs.len() - 2;
10938-
bad_epochs[idx].end_height += 1;
10939-
bad_epochs[idx + 1].start_height += 1;
10937+
let mut bad_epochs = (*STACKS_EPOCHS_MAINNET).clone();
10938+
bad_epochs[StacksEpochId::Epoch25].end_height += 1;
10939+
bad_epochs[StacksEpochId::Epoch30].start_height += 1;
1094010940

1094110941
let sortdb = SortitionDB::connect(
1094210942
&format!("{}/sortdb.sqlite", &path_root),
@@ -10951,14 +10951,14 @@ pub mod tests {
1095110951
.unwrap();
1095210952

1095310953
let db_epochs = SortitionDB::get_stacks_epochs(sortdb.conn()).unwrap();
10954-
assert_eq!(db_epochs, bad_epochs);
10954+
assert_eq!(db_epochs, bad_epochs.to_vec());
1095510955

1095610956
let fixed_sortdb = SortitionDB::connect(
1095710957
&format!("{}/sortdb.sqlite", &path_root),
1095810958
0,
1095910959
&BurnchainHeaderHash([0x00; 32]),
1096010960
0,
10961-
&STACKS_EPOCHS_MAINNET.to_vec(),
10961+
&STACKS_EPOCHS_MAINNET,
1096210962
PoxConstants::mainnet_default(),
1096310963
None,
1096410964
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)