Skip to content

Commit 5f3197c

Browse files
committed
use tenure-height as block-height for 2.x blocks, fix interpretation of marf key
1 parent 249136c commit 5f3197c

File tree

4 files changed

+86
-108
lines changed

4 files changed

+86
-108
lines changed

clarity/src/vm/database/clarity_db.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -935,10 +935,14 @@ impl<'a> ClarityDatabase<'a> {
935935
if current_tenure_height < tenure_height {
936936
return Ok(None);
937937
}
938-
if current_tenure_height == tenure_height {
939-
return Ok(Some(self.get_current_block_height()));
940-
}
941938
let current_height = self.get_current_block_height();
939+
// check if we're querying a 2.x block
940+
let id_bhh = self.get_index_block_header_hash(tenure_height)?;
941+
let epoch = self.get_stacks_epoch_for_block(&id_bhh)?;
942+
if !epoch.uses_nakamoto_blocks() {
943+
return Ok(Some(tenure_height));
944+
}
945+
942946
// query from the parent
943947
let query_tip = self.get_index_block_header_hash(current_height.saturating_sub(1))?;
944948
Ok(self

stackslib/src/chainstate/nakamoto/keys.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn ongoing_tenure_id() -> &'static str {
2323
"nakamoto::tenures::ongoing_tenure_id"
2424
}
2525

26-
/// MARF key to map the coinbase height of a tenure to its consensus hash
26+
/// MARF key to map the coinbase height of a tenure to its first block ID
2727
pub fn ongoing_tenure_coinbase_height(coinbase_height: u64) -> String {
2828
format!(
2929
"nakamoto::tenures::ongoing_tenure_coinbase_height::{}",

stackslib/src/clarity_vm/database/mod.rs

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,12 @@ pub trait GetTenureStartId {
4747
tip: &StacksBlockId,
4848
tenure_id_consensus_hash: &ConsensusHash,
4949
) -> Result<Option<TenureBlockId>, DBError>;
50-
fn get_tenure_ch_at_cb_height(
51-
&self,
52-
tip: &StacksBlockId,
53-
coinbase_height: u64,
54-
) -> Result<Option<ConsensusHash>, DBError>;
55-
fn conn(&self) -> &Connection;
5650
fn get_tenure_block_id_at_cb_height(
5751
&self,
5852
tip: &StacksBlockId,
5953
coinbase_height: u64,
60-
) -> Result<Option<TenureBlockId>, DBError> {
61-
let Some(tenure_ch) = self.get_tenure_ch_at_cb_height(tip, coinbase_height)? else {
62-
return Ok(None);
63-
};
64-
self.get_tenure_block_id(tip, &tenure_ch)
65-
}
54+
) -> Result<Option<StacksBlockId>, DBError>;
55+
fn conn(&self) -> &Connection;
6656
}
6757

6858
impl GetTenureStartId for StacksDBConn<'_> {
@@ -81,17 +71,17 @@ impl GetTenureStartId for StacksDBConn<'_> {
8171
.map(|block_id| TenureBlockId::from(block_id)))
8272
}
8373

84-
fn get_tenure_ch_at_cb_height(
74+
fn get_tenure_block_id_at_cb_height(
8575
&self,
8676
tip: &StacksBlockId,
8777
coinbase_height: u64,
88-
) -> Result<Option<ConsensusHash>, DBError> {
78+
) -> Result<Option<StacksBlockId>, DBError> {
8979
let opt_out = self
9080
.get_indexed(
9181
tip,
9282
&nakamoto_keys::ongoing_tenure_coinbase_height(coinbase_height),
9383
)?
94-
.map(|hex_inp| nakamoto_keys::parse_consensus_hash(&hex_inp))
84+
.map(|hex_inp| nakamoto_keys::parse_block_id(&hex_inp))
9585
.flatten();
9686
Ok(opt_out)
9787
}
@@ -117,17 +107,17 @@ impl GetTenureStartId for StacksDBTx<'_> {
117107
.map(|block_id| TenureBlockId::from(block_id)))
118108
}
119109

120-
fn get_tenure_ch_at_cb_height(
110+
fn get_tenure_block_id_at_cb_height(
121111
&self,
122112
tip: &StacksBlockId,
123113
coinbase_height: u64,
124-
) -> Result<Option<ConsensusHash>, DBError> {
114+
) -> Result<Option<StacksBlockId>, DBError> {
125115
let opt_out = self
126116
.get_indexed_ref(
127117
tip,
128118
&nakamoto_keys::ongoing_tenure_coinbase_height(coinbase_height),
129119
)?
130-
.map(|hex_inp| nakamoto_keys::parse_consensus_hash(&hex_inp))
120+
.map(|hex_inp| nakamoto_keys::parse_block_id(&hex_inp))
131121
.flatten();
132122
Ok(opt_out)
133123
}
@@ -151,13 +141,13 @@ impl GetTenureStartId for MARF<StacksBlockId> {
151141
self.sqlite_conn()
152142
}
153143

154-
fn get_tenure_ch_at_cb_height(
144+
fn get_tenure_block_id_at_cb_height(
155145
&self,
156146
tip: &StacksBlockId,
157147
coinbase_height: u64,
158-
) -> Result<Option<ConsensusHash>, DBError> {
148+
) -> Result<Option<StacksBlockId>, DBError> {
159149
let dbconn = StacksDBConn::new(self, ());
160-
dbconn.get_tenure_ch_at_cb_height(tip, coinbase_height)
150+
dbconn.get_tenure_block_id_at_cb_height(tip, coinbase_height)
161151
}
162152
}
163153

@@ -250,7 +240,7 @@ impl<'a> HeadersDB for HeadersDBConn<'a> {
250240
let tenure_block_id =
251241
GetTenureStartId::get_tenure_block_id_at_cb_height(&self.0, tip, tenure_height.into())
252242
.expect("FATAL: bad DB data for tenure height lookups")?;
253-
get_stacks_header_column(self.0.conn(), &tenure_block_id.0, "block_height", |r| {
243+
get_stacks_header_column(self.0.conn(), &tenure_block_id, "block_height", |r| {
254244
u64::from_row(r)
255245
.expect("FATAL: malformed block_height")
256246
.try_into()
@@ -499,7 +489,7 @@ impl<'a> HeadersDB for ChainstateTx<'a> {
499489
tenure_height.into(),
500490
)
501491
.expect("FATAL: bad DB data for tenure height lookups")?;
502-
get_stacks_header_column(self.deref(), &tenure_block_id.0, "block_height", |r| {
492+
get_stacks_header_column(self.deref(), &tenure_block_id, "block_height", |r| {
503493
u64::from_row(r)
504494
.expect("FATAL: malformed block_height")
505495
.try_into()
@@ -670,17 +660,12 @@ impl HeadersDB for MARF<StacksBlockId> {
670660
let tenure_block_id =
671661
GetTenureStartId::get_tenure_block_id_at_cb_height(self, tip, tenure_height.into())
672662
.expect("FATAL: bad DB data for tenure height lookups")?;
673-
get_stacks_header_column(
674-
self.sqlite_conn(),
675-
&tenure_block_id.0,
676-
"block_height",
677-
|r| {
678-
u64::from_row(r)
679-
.expect("FATAL: malformed block_height")
680-
.try_into()
681-
.expect("FATAL: blockchain too long")
682-
},
683-
)
663+
get_stacks_header_column(self.sqlite_conn(), &tenure_block_id, "block_height", |r| {
664+
u64::from_row(r)
665+
.expect("FATAL: malformed block_height")
666+
.try_into()
667+
.expect("FATAL: blockchain too long")
668+
})
684669
}
685670
}
686671

testnet/stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 59 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use stacks::net::api::getstackers::GetStackersResponse;
7070
use stacks::net::api::postblock_proposal::{
7171
BlockValidateReject, BlockValidateResponse, NakamotoBlockProposal, ValidateRejectCode,
7272
};
73+
use stacks::types::chainstate::StacksBlockId;
7374
use stacks::util::hash::hex_bytes;
7475
use stacks::util_lib::boot::boot_code_id;
7576
use stacks::util_lib::signed_structured_data::pox4::{
@@ -7671,6 +7672,8 @@ fn assert_block_info(
76717672
miner: &Value,
76727673
miner_spend: &clarity::vm::Value,
76737674
) {
7675+
info!("block info tuple data: {tuple0:#?}");
7676+
76747677
assert!(tuple0
76757678
.get("burnchain-header-hash")
76767679
.unwrap()
@@ -7816,7 +7819,7 @@ fn check_block_info() {
78167819

78177820
// Deploy this version with the Clarity 1 / 2 before epoch 3
78187821
let contract0_name = "test-contract-0";
7819-
let contract_clarity1 = "(define-read-only (get-info (height uint))
7822+
let contract_clarity1 = "(define-read-only (get-block-info (height uint))
78207823
{
78217824
burnchain-header-hash: (get-block-info? burnchain-header-hash height),
78227825
id-header-hash: (get-block-info? id-header-hash height),
@@ -7859,7 +7862,7 @@ fn check_block_info() {
78597862
&naka_conf,
78607863
&sender_addr,
78617864
contract0_name,
7862-
"get-info",
7865+
"get-block-info",
78637866
vec![&clarity::vm::Value::UInt(1)],
78647867
);
78657868
let tuple0 = result0.expect_tuple().unwrap().data_map;
@@ -7929,25 +7932,36 @@ fn check_block_info() {
79297932
let info = get_chain_info_result(&naka_conf).unwrap();
79307933
info!("Chain info: {:?}", info);
79317934
let last_stacks_block_height = info.stacks_tip_height as u128;
7935+
let last_stacks_tip = StacksBlockId::new(&info.stacks_tip_consensus_hash, &info.stacks_tip);
7936+
let (chainstate, _) = StacksChainState::open(
7937+
naka_conf.is_mainnet(),
7938+
naka_conf.burnchain.chain_id,
7939+
&naka_conf.get_chainstate_path_str(),
7940+
None,
7941+
)
7942+
.unwrap();
79327943

7933-
let result0 = call_read_only(
7934-
&naka_conf,
7935-
&sender_addr,
7936-
contract0_name,
7937-
"get-info",
7938-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 2)],
7939-
);
7940-
let tuple0 = result0.expect_tuple().unwrap().data_map;
7944+
let last_tenure_height: u128 =
7945+
NakamotoChainState::get_coinbase_height(&mut chainstate.index_conn(), &last_stacks_tip)
7946+
.unwrap()
7947+
.unwrap()
7948+
.into();
7949+
7950+
let get_block_info = |contract_name: &str, query_height: u128| {
7951+
let result = call_read_only(
7952+
&naka_conf,
7953+
&sender_addr,
7954+
contract_name,
7955+
"get-block-info",
7956+
vec![&clarity::vm::Value::UInt(query_height)],
7957+
);
7958+
result.expect_tuple().unwrap().data_map
7959+
};
7960+
7961+
let tuple0 = get_block_info(contract0_name, last_tenure_height - 1);
79417962
assert_block_info(&tuple0, &miner, &miner_spend);
79427963

7943-
let result1 = call_read_only(
7944-
&naka_conf,
7945-
&sender_addr,
7946-
contract1_name,
7947-
"get-info",
7948-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 2)],
7949-
);
7950-
let tuple1 = result1.expect_tuple().unwrap().data_map;
7964+
let tuple1 = get_block_info(contract1_name, last_tenure_height - 1);
79517965
assert_eq!(tuple0, tuple1);
79527966

79537967
let result3_tenure = call_read_only(
@@ -7981,14 +7995,8 @@ fn check_block_info() {
79817995
tuple0.get("miner-spend-winner")
79827996
);
79837997

7984-
let result3_block = call_read_only(
7985-
&naka_conf,
7986-
&sender_addr,
7987-
contract3_name,
7988-
"get-block-info",
7989-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 2)],
7990-
);
7991-
let tuple3_block1 = result3_block.expect_tuple().unwrap().data_map;
7998+
// this will point to the last block in the prior tenure (which should have been a 2.x block)
7999+
let tuple3_block1 = get_block_info(contract3_name, last_stacks_block_height - 2);
79928000
assert_eq!(
79938001
tuple3_block1.get("id-header-hash"),
79948002
tuple0.get("id-header-hash")
@@ -8038,25 +8046,17 @@ fn check_block_info() {
80388046
let info = get_chain_info_result(&naka_conf).unwrap();
80398047
info!("Chain info: {:?}", info);
80408048
let last_stacks_block_height = info.stacks_tip_height as u128;
8049+
let last_stacks_tip = StacksBlockId::new(&info.stacks_tip_consensus_hash, &info.stacks_tip);
8050+
let last_tenure_height: u128 =
8051+
NakamotoChainState::get_coinbase_height(&mut chainstate.index_conn(), &last_stacks_tip)
8052+
.unwrap()
8053+
.unwrap()
8054+
.into();
80418055

8042-
let result0 = call_read_only(
8043-
&naka_conf,
8044-
&sender_addr,
8045-
contract0_name,
8046-
"get-info",
8047-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 1)],
8048-
);
8049-
let tuple0 = result0.expect_tuple().unwrap().data_map;
8056+
let tuple0 = get_block_info(contract0_name, last_tenure_height);
80508057
assert_block_info(&tuple0, &miner, &miner_spend);
80518058

8052-
let result1 = call_read_only(
8053-
&naka_conf,
8054-
&sender_addr,
8055-
contract1_name,
8056-
"get-info",
8057-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 1)],
8058-
);
8059-
let tuple1 = result1.expect_tuple().unwrap().data_map;
8059+
let tuple1 = get_block_info(contract1_name, last_tenure_height);
80608060
assert_eq!(tuple0, tuple1);
80618061

80628062
let result3_tenure = call_read_only(
@@ -8102,11 +8102,15 @@ fn check_block_info() {
81028102
let tuple3_block2 = result3_block.expect_tuple().unwrap().data_map;
81038103
// There should have been a block change, so these should be different.
81048104
assert_ne!(tuple3_block1, tuple3_block2);
8105+
8106+
// tuple 0 fetches the id-header-hash for the first block of the tenure (block1)
8107+
8108+
let tuple3_block1 = get_block_info(contract3_name, last_stacks_block_height - 2);
81058109
assert_eq!(
8106-
tuple3_block2.get("id-header-hash"),
8110+
tuple3_block1.get("id-header-hash"),
81078111
tuple0.get("id-header-hash")
81088112
);
8109-
assert_eq!(tuple3_block2.get("header-hash"), tuple0.get("header-hash"));
8113+
assert_eq!(tuple3_block1.get("header-hash"), tuple0.get("header-hash"));
81108114
assert!(tuple3_block2
81118115
.get("time")
81128116
.unwrap()
@@ -8150,25 +8154,17 @@ fn check_block_info() {
81508154
let info = get_chain_info_result(&naka_conf).unwrap();
81518155
info!("Chain info: {:?}", info);
81528156
let last_stacks_block_height = info.stacks_tip_height as u128;
8157+
let last_stacks_tip = StacksBlockId::new(&info.stacks_tip_consensus_hash, &info.stacks_tip);
8158+
let last_tenure_height: u128 =
8159+
NakamotoChainState::get_coinbase_height(&mut chainstate.index_conn(), &last_stacks_tip)
8160+
.unwrap()
8161+
.unwrap()
8162+
.into();
81538163

8154-
let result0 = call_read_only(
8155-
&naka_conf,
8156-
&sender_addr,
8157-
contract0_name,
8158-
"get-info",
8159-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 1)],
8160-
);
8161-
let tuple0 = result0.expect_tuple().unwrap().data_map;
8164+
let tuple0 = get_block_info(contract0_name, last_tenure_height);
81628165
assert_block_info(&tuple0, &miner, &miner_spend);
81638166

8164-
let result1 = call_read_only(
8165-
&naka_conf,
8166-
&sender_addr,
8167-
contract1_name,
8168-
"get-info",
8169-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 1)],
8170-
);
8171-
let tuple1 = result1.expect_tuple().unwrap().data_map;
8167+
let tuple1 = get_block_info(contract1_name, last_tenure_height);
81728168
assert_eq!(tuple0, tuple1);
81738169

81748170
let result3_tenure = call_read_only(
@@ -8181,21 +8177,14 @@ fn check_block_info() {
81818177
let tuple3_tenure1a = result3_tenure.expect_tuple().unwrap().data_map;
81828178
assert_eq!(tuple3_tenure1, tuple3_tenure1a);
81838179

8184-
let result3_block = call_read_only(
8185-
&naka_conf,
8186-
&sender_addr,
8187-
contract3_name,
8188-
"get-block-info",
8189-
vec![&clarity::vm::Value::UInt(last_stacks_block_height - 1)],
8190-
);
8191-
let tuple3_block3 = result3_block.expect_tuple().unwrap().data_map;
8180+
let tuple3_block3 = get_block_info(contract3_name, last_stacks_block_height - 1);
81928181
// There should have been a block change, so these should be different.
81938182
assert_ne!(tuple3_block3, tuple3_block2);
81948183
assert_eq!(
8195-
tuple3_block3.get("id-header-hash"),
8184+
tuple3_block1.get("id-header-hash"),
81968185
tuple0.get("id-header-hash")
81978186
);
8198-
assert_eq!(tuple3_block3.get("header-hash"), tuple0.get("header-hash"));
8187+
assert_eq!(tuple3_block1.get("header-hash"), tuple0.get("header-hash"));
81998188
assert!(tuple3_block3
82008189
.get("time")
82018190
.unwrap()

0 commit comments

Comments
 (0)