Skip to content

Commit

Permalink
Merge pull request stacks-network#4930 from stacks-network/feat/marfe…
Browse files Browse the repository at this point in the history
…d-nakamoto-chain-state

MARF'ed Nakamoto chainstate
  • Loading branch information
saralab authored Jul 11, 2024
2 parents 3b0846a + cf6b8fa commit 3001794
Show file tree
Hide file tree
Showing 57 changed files with 4,749 additions and 4,667 deletions.
6 changes: 2 additions & 4 deletions clarity/src/vm/database/clarity_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ use stacks_common::types::chainstate::{
BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, SortitionId, StacksAddress, StacksBlockId,
VRFSeed,
};
use stacks_common::types::{
Address, StacksEpoch as GenericStacksEpoch, StacksEpochId, PEER_VERSION_EPOCH_2_0,
};
use stacks_common::types::{Address, StacksEpoch as GenericStacksEpoch, StacksEpochId};
use stacks_common::util::hash::{to_hex, Hash160, Sha256Sum, Sha512Trunc256Sum};

use super::clarity_store::SpecialCaseHandler;
Expand Down Expand Up @@ -328,7 +326,7 @@ impl BurnStateDB for NullBurnStateDB {
start_height: 0,
end_height: u64::MAX,
block_limit: ExecutionCost::max_value(),
network_epoch: PEER_VERSION_EPOCH_2_0,
network_epoch: 0,
})
}
fn get_stacks_epoch_by_epoch_id(&self, _epoch_id: &StacksEpochId) -> Option<StacksEpoch> {
Expand Down
4 changes: 2 additions & 2 deletions clarity/src/vm/docs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2746,12 +2746,12 @@ pub fn make_json_api_reference() -> String {
#[cfg(test)]
mod test {
use stacks_common::address::AddressHashMode;
use stacks_common::consts::CHAIN_ID_TESTNET;
use stacks_common::consts::{CHAIN_ID_TESTNET, PEER_VERSION_EPOCH_2_1};
use stacks_common::types::chainstate::{
BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, SortitionId, StacksAddress,
StacksBlockId, VRFSeed,
};
use stacks_common::types::{Address, StacksEpochId, PEER_VERSION_EPOCH_2_1};
use stacks_common::types::{Address, StacksEpochId};
use stacks_common::util::hash::hex_bytes;

use super::{get_input_type_string, make_all_api_reference, make_json_api_reference};
Expand Down
3 changes: 2 additions & 1 deletion clarity/src/vm/test_util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use stacks_common::address::{AddressHashMode, C32_ADDRESS_VERSION_TESTNET_SINGLE
use stacks_common::consts::{
BITCOIN_REGTEST_FIRST_BLOCK_HASH, BITCOIN_REGTEST_FIRST_BLOCK_HEIGHT,
BITCOIN_REGTEST_FIRST_BLOCK_TIMESTAMP, FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH,
PEER_VERSION_EPOCH_2_0,
};
use stacks_common::types::chainstate::{
BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, SortitionId, StacksAddress, StacksBlockId,
StacksPrivateKey, StacksPublicKey, VRFSeed,
};
use stacks_common::types::{StacksEpochId, PEER_VERSION_EPOCH_2_0};
use stacks_common::types::StacksEpochId;

use crate::vm::ast::ASTRules;
use crate::vm::costs::ExecutionCost;
Expand Down
29 changes: 29 additions & 0 deletions stacks-common/src/libcommon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,35 @@ pub mod consts {
/// The number of StackerDB slots each signing key needs
/// to use to participate in DKG and block validation signing.
pub const SIGNER_SLOTS_PER_USER: u32 = 13;

/// peer version (big-endian)
/// first byte == major network protocol version (currently 0x18)
/// second and third bytes are unused
/// fourth byte == highest epoch supported by this node
pub const PEER_VERSION_MAINNET_MAJOR: u32 = 0x18000000;
pub const PEER_VERSION_TESTNET_MAJOR: u32 = 0xfacade00;

pub const PEER_VERSION_EPOCH_1_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_05: u8 = 0x05;
pub const PEER_VERSION_EPOCH_2_1: u8 = 0x06;
pub const PEER_VERSION_EPOCH_2_2: u8 = 0x07;
pub const PEER_VERSION_EPOCH_2_3: u8 = 0x08;
pub const PEER_VERSION_EPOCH_2_4: u8 = 0x09;
pub const PEER_VERSION_EPOCH_2_5: u8 = 0x0a;
pub const PEER_VERSION_EPOCH_3_0: u8 = 0x0b;

/// this should be updated to the latest network epoch version supported by
/// this node. this will be checked by the `validate_epochs()` method.
pub const PEER_NETWORK_EPOCH: u32 = PEER_VERSION_EPOCH_2_5 as u32;

/// set the fourth byte of the peer version
pub const PEER_VERSION_MAINNET: u32 = PEER_VERSION_MAINNET_MAJOR | PEER_NETWORK_EPOCH;
pub const PEER_VERSION_TESTNET: u32 = PEER_VERSION_TESTNET_MAJOR | PEER_NETWORK_EPOCH;

/// network identifiers
pub const NETWORK_ID_MAINNET: u32 = 0x17000000;
pub const NETWORK_ID_TESTNET: u32 = 0xff000000;
}

/// This test asserts that the constant above doesn't change.
Expand Down
5 changes: 0 additions & 5 deletions stacks-common/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ pub trait Address: Clone + fmt::Debug + fmt::Display {
fn is_burn(&self) -> bool;
}

pub const PEER_VERSION_EPOCH_1_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_05: u8 = 0x05;
pub const PEER_VERSION_EPOCH_2_1: u8 = 0x06;

// sliding burnchain window over which a miner's past block-commit payouts will be used to weight
// its current block-commit in a sortition.
// This is the value used in epoch 2.x
Expand Down
69 changes: 69 additions & 0 deletions stackslib/src/chainstate/burn/db/sortdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,14 @@ pub trait SortitionHandle {
/// Returns Err(..) on DB errors
fn get_nakamoto_tip(&self) -> Result<Option<(ConsensusHash, BlockHeaderHash, u64)>, db_error>;

/// Get the block ID of the highest-processed Nakamoto block on this history.
fn get_nakamoto_tip_block_id(&self) -> Result<Option<StacksBlockId>, db_error> {
let Some((ch, bhh, _)) = self.get_nakamoto_tip()? else {
return Ok(None);
};
Ok(Some(StacksBlockId::new(&ch, &bhh)))
}

/// is the given block a descendant of `potential_ancestor`?
/// * block_at_burn_height: the burn height of the sortition that chose the stacks block to check
/// * potential_ancestor: the stacks block hash of the potential ancestor
Expand Down Expand Up @@ -1813,6 +1821,67 @@ impl<'a> SortitionHandleTx<'a> {

if cur_epoch.epoch_id >= StacksEpochId::Epoch30 {
// Nakamoto blocks are always processed in order since the chain can't fork
// arbitrarily.
//
// However, a "benign" fork can arise when a late tenure-change is processed. This
// would happen if
//
// 1. miner A wins sortition and produces a tenure-change;
// 2. miner B wins sortition, and signers sign its tenure-change;
// 3. miner C wins sortition by confirming miner A's last-block
//
// Depending on the timing of things, signers could end up signing both miner B and
// miner C's tenure-change blocks, which are in conflict. The Stacks node must be able
// to handle this case; it does so simply by processing both blocks (as Stacks forks),
// and letting signers figure out which one is canonical.
//
// As a result, only update the canonical Nakamoto tip if the given block is higher
// than the existing tip for this sortiton (because it represents more overall signer
// votes).
let current_sortition_tip : Option<(ConsensusHash, BlockHeaderHash, u64)> = self.query_row_and_then(
"SELECT consensus_hash,block_hash,block_height FROM stacks_chain_tips WHERE sortition_id = ?1 ORDER BY block_height DESC LIMIT 1",
rusqlite::params![&burn_tip.sortition_id],
|row| Ok((row.get_unwrap(0), row.get_unwrap(1), (u64::try_from(row.get_unwrap::<_, i64>(2)).expect("FATAL: block height too high"))))
).optional()?;

if let Some((cur_ch, cur_bhh, cur_height)) = current_sortition_tip {
let will_replace = if cur_height < stacks_block_height {
true
} else if cur_height > stacks_block_height {
false
} else {
if &cur_ch == consensus_hash {
// same sortition (i.e. nakamoto block)
// no replacement
false
} else {
// tips come from different sortitions
// break ties by going with the latter-signed block
let sn_current = SortitionDB::get_block_snapshot_consensus(self, &cur_ch)?
.ok_or(db_error::NotFoundError)?;
let sn_accepted =
SortitionDB::get_block_snapshot_consensus(self, &consensus_hash)?
.ok_or(db_error::NotFoundError)?;
sn_current.block_height < sn_accepted.block_height
}
};

debug!("Setting Stacks tip as accepted";
"replace?" => will_replace,
"current_tip_consensus_hash" => %cur_ch,
"current_tip_block_header_hash" => %cur_bhh,
"current_tip_block_id" => %StacksBlockId::new(&cur_ch, &cur_bhh),
"current_tip_height" => cur_height,
"accepted_tip_consensus_hash" => %consensus_hash,
"accepted_tip_block_header_hash" => %stacks_block_hash,
"accepted_tip_block_id" => %StacksBlockId::new(consensus_hash, stacks_block_hash),
"accepted_tip_height" => stacks_block_height);

if !will_replace {
return Ok(());
}
}

self.update_canonical_stacks_tip(
&burn_tip.sortition_id,
consensus_hash,
Expand Down
29 changes: 18 additions & 11 deletions stackslib/src/chainstate/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use crate::chainstate::stacks::events::{
StacksBlockEventData, StacksTransactionEvent, StacksTransactionReceipt, TransactionOrigin,
};
use crate::chainstate::stacks::index::marf::MARFOpenOpts;
use crate::chainstate::stacks::index::MarfTrieId;
use crate::chainstate::stacks::index::{Error as IndexError, MarfTrieId};
use crate::chainstate::stacks::miner::{signal_mining_blocked, signal_mining_ready, MinerStatus};
use crate::chainstate::stacks::{
Error as ChainstateError, StacksBlock, StacksBlockHeader, TransactionPayload,
Expand Down Expand Up @@ -252,6 +252,7 @@ pub enum Error {
NoSortitions,
FailedToProcessSortition(BurnchainError),
DBError(DBError),
IndexError(IndexError),
NotPrepareEndBlock,
NotPoXAnchorBlock,
NotInPreparePhase,
Expand All @@ -278,6 +279,12 @@ impl From<DBError> for Error {
}
}

impl From<IndexError> for Error {
fn from(o: IndexError) -> Error {
Error::IndexError(o)
}
}

pub trait RewardSetProvider {
fn get_reward_set(
&self,
Expand Down Expand Up @@ -3320,11 +3327,11 @@ impl<

// update cost estimator
if let Some(ref mut estimator) = self.cost_estimator {
let stacks_epoch = self
.sortition_db
.index_conn()
.get_stacks_epoch_by_epoch_id(&block_receipt.evaluated_epoch)
.expect("Could not find a stacks epoch.");
let stacks_epoch = SortitionDB::get_stacks_epoch_by_epoch_id(
self.sortition_db.conn(),
&block_receipt.evaluated_epoch,
)?
.expect("Could not find a stacks epoch.");
estimator.notify_block(
&block_receipt.tx_receipts,
&stacks_epoch.block_limit,
Expand All @@ -3334,11 +3341,11 @@ impl<

// update fee estimator
if let Some(ref mut estimator) = self.fee_estimator {
let stacks_epoch = self
.sortition_db
.index_conn()
.get_stacks_epoch_by_epoch_id(&block_receipt.evaluated_epoch)
.expect("Could not find a stacks epoch.");
let stacks_epoch = SortitionDB::get_stacks_epoch_by_epoch_id(
self.sortition_db.conn(),
&block_receipt.evaluated_epoch,
)?
.expect("Could not find a stacks epoch.");
if let Err(e) =
estimator.notify_block(&block_receipt, &stacks_epoch.block_limit)
{
Expand Down
Loading

0 comments on commit 3001794

Please sign in to comment.