feat: handle tenure-height with at-block before epoch 3.0

Also including some other improvements from PR review.
This commit is contained in:
Brice Dobry
2024-05-14 16:20:36 -04:00
parent 302af761b7
commit 2b4b1c14bf
6 changed files with 105 additions and 26 deletions

View File

@@ -74,7 +74,7 @@ pub struct Environment<'a, 'b, 'hooks> {
}
pub struct OwnedEnvironment<'a, 'hooks> {
context: GlobalContext<'a, 'hooks>,
pub(crate) context: GlobalContext<'a, 'hooks>,
call_stack: CallStack,
}
@@ -1964,18 +1964,6 @@ impl CallStack {
}
}
#[cfg(any(test, feature = "testing"))]
impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
pub fn set_tenure_height(&mut self, tenure_height: u32) {
self.context.database.begin();
self.context
.database
.set_tenure_height(tenure_height)
.unwrap();
self.context.database.commit().unwrap();
}
}
#[cfg(test)]
mod test {
use stacks_common::types::chainstate::StacksAddress;

View File

@@ -858,6 +858,12 @@ impl<'a> ClarityDatabase<'a> {
/// Returns the tenure height of the current block.
pub fn get_tenure_height(&mut self) -> Result<u32> {
if self.get_clarity_epoch_version()? < StacksEpochId::Epoch30 {
// Before epoch 3.0, the tenure height was not stored in the
// Clarity state. Instead, it was the same as the block height.
return Ok(self.get_current_block_height());
}
self.get_data(TENURE_HEIGHT_KEY)?
.ok_or_else(|| {
InterpreterError::Expect("No tenure height in stored Clarity state".into()).into()
@@ -874,6 +880,11 @@ impl<'a> ClarityDatabase<'a> {
/// tenure, this height must be incremented before evaluating any
/// transactions in the block.
pub fn set_tenure_height(&mut self, height: u32) -> Result<()> {
if self.get_clarity_epoch_version()? < StacksEpochId::Epoch30 {
return Err(Error::Interpreter(InterpreterError::Expect(
"Setting tenure height in Clarity state is not supported before epoch 3.0".into(),
)));
}
self.put_data(TENURE_HEIGHT_KEY, &height)
}

View File

@@ -35,6 +35,18 @@ mod simple_apply_eval;
mod traits;
mod variables;
#[cfg(any(test, feature = "testing"))]
impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> {
pub fn set_tenure_height(&mut self, tenure_height: u32) {
self.context.database.begin();
self.context
.database
.set_tenure_height(tenure_height)
.unwrap();
self.context.database.commit().unwrap();
}
}
macro_rules! epochs_template {
($($epoch:ident,)*) => {
#[template]
@@ -160,7 +172,11 @@ impl MemoryEnvironmentGenerator {
pub struct TopLevelMemoryEnvironmentGenerator(MemoryBackingStore);
impl TopLevelMemoryEnvironmentGenerator {
pub fn get_env(&mut self, epoch: StacksEpochId) -> OwnedEnvironment {
let mut owned_env = OwnedEnvironment::new(self.0.as_clarity_db(), epoch);
let mut db = self.0.as_clarity_db();
db.begin();
db.set_clarity_epoch_version(epoch).unwrap();
db.commit().unwrap();
let mut owned_env = OwnedEnvironment::new(db, epoch);
if epoch >= StacksEpochId::Epoch30 {
owned_env.set_tenure_height(1);
}

View File

@@ -164,11 +164,13 @@ impl ClarityTestSim {
let cur_epoch = Self::check_and_bump_epoch(&mut store, &headers_db, &burn_db);
let mut db = store.as_clarity_db(&headers_db, &burn_db);
db.begin();
db.set_tenure_height(self.tenure_height as u32 + if new_tenure { 1 } else { 0 })
.expect("FAIL: unable to set tenure height in Clarity database");
db.commit()
.expect("FAIL: unable to commit tenure height in Clarity database");
if cur_epoch >= StacksEpochId::Epoch30 {
db.begin();
db.set_tenure_height(self.tenure_height as u32 + if new_tenure { 1 } else { 0 })
.expect("FAIL: unable to set tenure height in Clarity database");
db.commit()
.expect("FAIL: unable to commit tenure height in Clarity database");
}
let mut block_conn =
ClarityBlockConnection::new_test_conn(store, &headers_db, &burn_db, cur_epoch);
@@ -215,11 +217,13 @@ impl ClarityTestSim {
debug!("Execute block in epoch {}", &cur_epoch);
let mut db = store.as_clarity_db(&headers_db, &burn_db);
db.begin();
db.set_tenure_height(self.tenure_height as u32 + if new_tenure { 1 } else { 0 })
.expect("FAIL: unable to set tenure height in Clarity database");
db.commit()
.expect("FAIL: unable to commit tenure height in Clarity database");
if cur_epoch >= StacksEpochId::Epoch30 {
db.begin();
db.set_tenure_height(self.tenure_height as u32 + if new_tenure { 1 } else { 0 })
.expect("FAIL: unable to set tenure height in Clarity database");
db.commit()
.expect("FAIL: unable to commit tenure height in Clarity database");
}
let mut owned_env = OwnedEnvironment::new_toplevel(db);
f(&mut owned_env)
};

View File

@@ -1395,3 +1395,61 @@ fn test_block_heights_across_versions_traits() {
assert_eq!(Value::okay(Value::UInt(20)).unwrap(), res2.0);
});
}
#[test]
fn test_block_heights_at_block() {
let mut sim = ClarityTestSim::new();
sim.epoch_bounds = vec![0, 1, 2, 3, 4, 5, 6, 7];
let contract_identifier = QualifiedContractIdentifier::local("test-contract").unwrap();
// Advance to epoch 3.0
while sim.block_height <= 7 {
sim.execute_next_block(|_env| {});
}
let block_height = sim.block_height as u128;
sim.execute_next_block_as_conn(|conn| {
let epoch = conn.get_epoch();
assert_eq!(epoch, StacksEpochId::Epoch30);
let contract =r#"
(define-private (test-tenure) (at-block (unwrap-panic (get-block-info? id-header-hash u0)) tenure-height))
(define-private (test-stacks) (at-block (unwrap-panic (get-block-info? id-header-hash u1)) stacks-block-height))
"#;
conn.as_transaction(|clarity_db| {
// Analyze the contract
let (ast, analysis) = clarity_db.analyze_smart_contract(
&contract_identifier,
ClarityVersion::Clarity3,
&contract,
ASTRules::PrecheckSize,
).unwrap();
// Publish the contract
clarity_db
.initialize_smart_contract(
&contract_identifier,
ClarityVersion::Clarity3,
&ast,
contract,
None,
|_, _| false,
).unwrap();
});
// Call the contracts and validate the results
let mut tx = conn.start_transaction_processing();
assert_eq!(
Value::UInt(0),
tx.eval_read_only(&contract_identifier, "(test-tenure)")
.unwrap()
);
assert_eq!(
Value::UInt(1),
tx.eval_read_only(&contract_identifier, "(test-stacks)")
.unwrap()
);
});
}

View File

@@ -101,8 +101,10 @@ fn new_block<'a, 'b>(
block.as_free_transaction(|tx_conn| {
tx_conn
.with_clarity_db(|db| {
let tenure_height = db.get_tenure_height().unwrap_or(0);
db.set_tenure_height(tenure_height + 1).unwrap();
if db.get_clarity_epoch_version().unwrap() >= StacksEpochId::Epoch30 {
let tenure_height = db.get_tenure_height().unwrap_or(0);
db.set_tenure_height(tenure_height + 1).unwrap();
}
Ok(())
})
.unwrap();