Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MARF'ed Nakamoto chainstate #4930

Merged
merged 91 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 87 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
b67b629
chore: strip duplicate peer epoch ID
jcnelson Jun 28, 2024
fe27f92
chore: strip duplicate peer version ID
jcnelson Jun 28, 2024
ed78166
chore: strip duplicate peer version ID
jcnelson Jun 28, 2024
1cf1048
chore: DRY up peer versions
jcnelson Jun 28, 2024
2ecf14d
fix: only advance canonical nakamoto fork in the sortition DB if it's…
jcnelson Jun 28, 2024
af9d5d7
fix: remove sortition DB-specific functions from IndexDBConn
jcnelson Jun 28, 2024
4fd033f
fix: query reward set off of a Stacks tip via the MARF, which for the…
jcnelson Jun 28, 2024
f1db79e
chore: remove tests that cannot be run without the MARF (and test the…
jcnelson Jun 28, 2024
d7e14b8
chore: API sync
jcnelson Jun 28, 2024
e5642e5
feat: MARF the Nakamoto chain state. Any query that is not indexed s…
jcnelson Jun 28, 2024
b29a93b
chore: debug
jcnelson Jun 28, 2024
1782417
chore: fix nakamoto staging blocks table to record signing weight and…
jcnelson Jun 28, 2024
fdd9039
chore: MARF the nakamoto tenures table, and remove the `tenure_index`…
jcnelson Jun 28, 2024
8b6bbf9
chore: strip out MARF-dependent tests and move them to a separate tes…
jcnelson Jun 28, 2024
60c8764
feat: malleablize blocks when processing them in each TestPeer-driven…
jcnelson Jun 28, 2024
7ce5771
chore: API sync
jcnelson Jun 28, 2024
c09c87e
chore: API sync
jcnelson Jun 28, 2024
fc126ad
chore: API sync
jcnelson Jun 28, 2024
194ae04
chore: API sync and DB migrations
jcnelson Jun 28, 2024
6e49963
chore: API sync
jcnelson Jun 28, 2024
99c5fc9
chore: API sync
jcnelson Jun 28, 2024
a3ce626
chore: close #4900 by relying on the MARF for querying the tenure-sta…
jcnelson Jun 28, 2024
8e2c81c
chore: better debugging
jcnelson Jun 28, 2024
87a676b
chore: bump peer epoch
jcnelson Jun 28, 2024
922152a
chore: API sync
jcnelson Jun 28, 2024
1a60607
chore: API sync
jcnelson Jun 28, 2024
06dc85c
chore: API sync
jcnelson Jun 28, 2024
5ebb554
chore: API sync -- use nakamoto tip from p2p state machine to query c…
jcnelson Jun 28, 2024
f919830
chore: API sync
jcnelson Jun 28, 2024
8fca258
fix: dead code
jcnelson Jun 29, 2024
746ee8a
chore: log decode failures (indicates 404)
jcnelson Jun 29, 2024
9df0155
fix: a downloader set is empty if there are actually no downloaders, …
jcnelson Jun 29, 2024
aba1587
chore: log more failure modes, and validate the unconfirmed tenure ag…
jcnelson Jun 29, 2024
cec61ea
chore: trace --> test_debug
jcnelson Jun 29, 2024
6206ce9
chore: API sync with new MARF'ed chainstate
jcnelson Jun 29, 2024
393f2f0
chore: store and verify storage of malleablized blocks
jcnelson Jun 29, 2024
6c34a0d
chore: only log HTTP convo status if it's not idle
jcnelson Jun 29, 2024
1ed1c30
chore: clean up stacks tip representation, and use MARF'ed chainstate…
jcnelson Jun 29, 2024
9ef9171
chore: use MARF'ed chainstate API
jcnelson Jun 29, 2024
4663ea0
chore: use MARF'ed chainstate API
jcnelson Jun 29, 2024
e662a4d
chore: make malleablizable blocks by default when synthesizing peers …
jcnelson Jun 29, 2024
bfea1ea
chore: synthesize and process malleablized blocks when producing a te…
jcnelson Jun 29, 2024
614ca85
chore: API sync
jcnelson Jun 29, 2024
1e5f342
chore: API sync
jcnelson Jun 29, 2024
27d6d41
fix: remove sortition DB-specific functions
jcnelson Jun 29, 2024
0ebce58
chore: API sync, add more logging, remove dead code
jcnelson Jun 29, 2024
dbd4c15
chore: API sync
jcnelson Jun 29, 2024
c4b2efc
chore: API sync
jcnelson Jun 29, 2024
3c885f8
WIP: follower_bootup work
jcnelson Jun 29, 2024
f97502f
feat: get_account_result() helper method
jcnelson Jun 29, 2024
434b318
chore: fmt
jcnelson Jul 1, 2024
8393e1d
refactor: expose get_nakamoto_tenure_vrf_proof
jcnelson Jul 1, 2024
7b0c8f3
docs: get_ongoing_tenure returns None for epoch2x blocks
jcnelson Jul 1, 2024
64ab7b3
chore: add test coverage for get_highest_block_header_in_tenure()
jcnelson Jul 1, 2024
b2fb824
chore: remove signers voting tests (since this code won't be used)
jcnelson Jul 1, 2024
ad12117
chore: remove nonexistant imports
jcnelson Jul 1, 2024
fa71e62
chore: these tests no longer test functionality that will be used
jcnelson Jul 1, 2024
63de87a
chore: remove import for nonexistant module
jcnelson Jul 1, 2024
05258d9
chore: accept fix for #4938
jcnelson Jul 1, 2024
74a6275
chore: API sync; log getnakamotoinv response
jcnelson Jul 1, 2024
815e1d9
chore: remove dead code
jcnelson Jul 1, 2024
52ccde4
chore: remove dead code
jcnelson Jul 1, 2024
d44af3d
chore: query invnetory state from network-given tip
jcnelson Jul 1, 2024
a482d54
chore: test get_parent_stacks_tip() by looking at the tip and parent …
jcnelson Jul 1, 2024
2e1fbe8
chore: NetworkHandle can be Clone'd
jcnelson Jul 1, 2024
e377b2b
chore: serve NetworkHandle from relayer
jcnelson Jul 1, 2024
219b421
chore: API sync
jcnelson Jul 1, 2024
beb777c
chore: API sync
jcnelson Jul 1, 2024
b69703e
chore: test get_parent_stacks_tip() in nakamoto bootup
jcnelson Jul 1, 2024
7144b19
feat: broadcast Nakamoto blocks to p2p state machine, and rework the …
jcnelson Jul 1, 2024
c9df911
chore: consolidate last-committed tip data and directly query te chai…
jcnelson Jul 1, 2024
c70df54
chore: fix follower_bootup
jcnelson Jul 1, 2024
0cdfa54
Fix number of signatures to check against in mine 2 nakamoto tenures
jferrant Jul 1, 2024
b9f2f5f
chore: fmt
jcnelson Jul 1, 2024
642bef7
chore: address (some) failing unit tests
jcnelson Jul 2, 2024
c63534f
fix: process burn ops when a tenure-change tx is found
jcnelson Jul 2, 2024
e9f81a8
fix: fix failing unit tests
jcnelson Jul 2, 2024
95e37b7
fix: fix failing unit test
jcnelson Jul 2, 2024
6060b8e
fix: use malleablized blocks
jcnelson Jul 2, 2024
e794530
chore: remove unused code
jcnelson Jul 2, 2024
b9db8b5
Merge branch 'develop' into feat/marfed-nakamoto-chain-state
jcnelson Jul 2, 2024
fefac85
fix: typo
jcnelson Jul 9, 2024
8668e5b
Merge branch 'develop' into feat/marfed-nakamoto-chain-state, and add…
jcnelson Jul 9, 2024
85492aa
chore: fix unit tests
jcnelson Jul 10, 2024
9578d5e
chore: address PR feedback and get remaining integration tests to pass
jcnelson Jul 10, 2024
e3a0659
Merge branch 'develop' into feat/marfed-nakamoto-chain-state
jcnelson Jul 10, 2024
96eb322
fix: don't tie-break nakamoto blocks using block hash; just go with w…
jcnelson Jul 11, 2024
4f757a4
chore: remove ways to address blocks by sighash, and use block hash i…
jcnelson Jul 11, 2024
74cc300
fix: temporarily skip some mutant checks
jcnelson Jul 11, 2024
64a4094
Merge branch 'develop' into feat/marfed-nakamoto-chain-state
jcnelson Jul 11, 2024
cf6b8fa
chore: remove unneeded test notes; permit DB version 6 in older chain…
jcnelson Jul 11, 2024
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
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;
jcnelson marked this conversation as resolved.
Show resolved Hide resolved
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;

jcnelson marked this conversation as resolved.
Show resolved Hide resolved
// 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