diff --git a/components/clarity-repl/src/repl/datastore.rs b/components/clarity-repl/src/repl/datastore.rs index de78a0399..434c9c1cb 100644 --- a/components/clarity-repl/src/repl/datastore.rs +++ b/components/clarity-repl/src/repl/datastore.rs @@ -805,6 +805,7 @@ impl Datastore { if epoch == self.current_epoch { return; } + clarity_datastore.put("vm-epoch::epoch-version", &format!("{:08x}", epoch as u32)); self.current_epoch = epoch; self.current_epoch_start_height = self.stacks_chain_height; if epoch >= StacksEpochId::Epoch30 { @@ -989,16 +990,23 @@ impl BurnStateDB for Datastore { } fn get_tip_burn_block_height(&self) -> Option { - let current_chain_tip = self.current_chain_tip.borrow(); - if let Some(height) = self.get_burn_block_height_for_block(¤t_chain_tip) { - return Some(height); - } + use StacksEpochId::*; + match self.current_epoch { + Epoch10 | Epoch20 | Epoch2_05 | Epoch21 | Epoch22 | Epoch23 | Epoch24 | Epoch25 => { + let current_chain_tip = self.current_chain_tip.borrow(); + if let Some(height) = self.get_burn_block_height_for_block(¤t_chain_tip) { + return Some(height); + } - return self - .remote_block_info_cache - .borrow() - .get(¤t_chain_tip) - .map(|block| block.burn_block_height); + self.remote_block_info_cache + .borrow() + .get(¤t_chain_tip) + .map(|block| block.burn_block_height) + } + // preserve the 3.0 and 3.1 special behavior of burn-block-height + // https://github.com/stacks-network/stacks-core/pull/5524 + Epoch30 | Epoch31 => Some(self.burn_chain_height), + } } fn get_tip_sortition_id(&self) -> Option { diff --git a/components/clarity-repl/src/repl/session.rs b/components/clarity-repl/src/repl/session.rs index 5225e235f..16ad03fcb 100644 --- a/components/clarity-repl/src/repl/session.rs +++ b/components/clarity-repl/src/repl/session.rs @@ -1693,8 +1693,7 @@ mod tests { let _ = session.advance_burn_chain_tip(10000); - assert_eq!(session.process_console_input("(at-block (unwrap-panic (get-stacks-block-info? id-header-hash u19000)) burn-block-height)").1[0], "u18999".green().to_string()); - assert_eq!(session.process_console_input("(at-block (unwrap-panic (get-stacks-block-info? id-header-hash u20000)) burn-block-height)").1[0], "u19999".green().to_string()); + assert_eq!(session.process_console_input("(at-block (unwrap-panic (get-stacks-block-info? id-header-hash u19000)) burn-block-height)").1[0], "u20021".green().to_string()); } #[test] @@ -1813,4 +1812,120 @@ mod tests { assert!(time_block_2 - time_block_1 == 600); } + + #[test] + fn burn_block_height_behavior_epoch2_5() { + let settings = SessionSettings::default(); + let mut session = Session::new(settings); + session.start().expect("session could not start"); + session.update_epoch(StacksEpochId::Epoch25); + + let snippet = [ + "(define-read-only (get-burn (height uint))", + " (let ((id (unwrap-panic (get-block-info? id-header-hash height))))", + " (at-block id burn-block-height)))", + ] + .join("\n"); + + let contract = ClarityContractBuilder::new() + .code_source(snippet) + .clarity_version(ClarityVersion::Clarity2) + .epoch(StacksEpochId::Epoch25) + .build(); + + session.deploy_contract(&contract, false, None).unwrap(); + session.advance_burn_chain_tip(10); + + let result = run_session_snippet(&mut session, "block-height"); + assert_eq!(result, Value::UInt(10)); + let result = run_session_snippet(&mut session, "burn-block-height"); + assert_eq!(result, Value::UInt(9)); + let result = run_session_snippet( + &mut session, + format!("(contract-call? .{} get-burn u6)", contract.name).as_str(), + ); + assert_eq!(result, Value::UInt(5)); + } + + #[test] + fn burn_block_height_behavior_epoch3_0() { + // test that clarinet preserves the 3.0 and 3.1 special behavior of burn-block-height + // https://github.com/stacks-network/stacks-core/pull/5524 + let settings = SessionSettings::default(); + let mut session = Session::new(settings); + session.start().expect("session could not start"); + session.update_epoch(StacksEpochId::Epoch30); + + let snippet = [ + "(define-read-only (get-burn (height uint))", + " (let ((id (unwrap-panic (get-stacks-block-info? id-header-hash height))))", + " (at-block id burn-block-height)))", + ] + .join("\n"); + + let contract = ClarityContractBuilder::new() + .code_source(snippet) + .clarity_version(ClarityVersion::Clarity3) + .epoch(StacksEpochId::Epoch30) + .build(); + + session.deploy_contract(&contract, false, None).unwrap(); + session.advance_burn_chain_tip(10); + + let result = run_session_snippet(&mut session, "stacks-block-height"); + assert_eq!(result, Value::UInt(11)); + let result = run_session_snippet(&mut session, "burn-block-height"); + assert_eq!(result, Value::UInt(11)); + let result = run_session_snippet( + &mut session, + format!("(contract-call? .{} get-burn u8)", contract.name).as_str(), + ); + assert_eq!(result, Value::UInt(11)); + } + + #[test] + fn burn_block_height_behavior_epoch3_0_contract_in_2_5() { + let settings = SessionSettings::default(); + let mut session = Session::new(settings); + session.start().expect("session could not start"); + session.update_epoch(StacksEpochId::Epoch25); + + let snippet = [ + "(define-read-only (get-burn (height uint))", + " (let ((id (unwrap-panic (get-block-info? id-header-hash height))))", + " (at-block id burn-block-height)))", + ] + .join("\n"); + + let contract = ClarityContractBuilder::new() + .name("contract-2-5") + .code_source(snippet.clone()) + .clarity_version(ClarityVersion::Clarity2) + .epoch(StacksEpochId::Epoch25) + .build(); + + session.deploy_contract(&contract, false, None).unwrap(); + session.advance_burn_chain_tip(10); + + session.update_epoch(StacksEpochId::Epoch30); + + session.advance_burn_chain_tip(10); + + let result = run_session_snippet(&mut session, "stacks-block-height"); + assert_eq!(result, Value::UInt(21)); + + // calling a 2.5 contract in epoch 3.0 has the same behavior as epoch 2.5 + + let result = run_session_snippet( + &mut session, + format!("(contract-call? .{} get-burn u8)", contract.name).as_str(), + ); + assert_eq!(result, Value::UInt(7)); + + let result = run_session_snippet( + &mut session, + format!("(contract-call? .{} get-burn u18)", contract.name).as_str(), + ); + assert_eq!(result, Value::UInt(21)); + } } diff --git a/components/clarity-repl/tests/session_with_remote_data.rs b/components/clarity-repl/tests/session_with_remote_data.rs index 4de0793a6..ed393cca6 100644 --- a/components/clarity-repl/tests/session_with_remote_data.rs +++ b/components/clarity-repl/tests/session_with_remote_data.rs @@ -154,7 +154,7 @@ fn it_can_get_heights() { assert_eq!(result, Value::UInt(42000)); let snippet = format!("(at-block {hash} burn-block-height)"); let result = eval_snippet(&mut session, &snippet); - assert_eq!(result, Value::UInt(5560)); + assert_eq!(result, Value::UInt(6603)); let snippet = format!("(at-block {hash} tenure-height)"); let result = eval_snippet(&mut session, &snippet); assert_eq!(result, Value::UInt(3302));