Skip to content

POC/WIP block simulate endpoint #6346

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

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
39 changes: 39 additions & 0 deletions stackslib/src/chainstate/stacks/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2122,6 +2122,45 @@ impl StacksChainState {
self.clarity_state.with_marf(f)
}

pub fn with_simulated_clarity_tx<F, R>(
&mut self,
burn_dbconn: &dyn BurnStateDB,
parent_block_id: &StacksBlockId,
new_block_id: &StacksBlockId,
to_do: F,
) -> Option<R>
where
F: FnOnce(&mut ClarityTx) -> R,
{
match NakamotoChainState::get_block_header(self.db(), parent_block_id) {
Ok(Some(_)) => {}
Ok(None) => {
return None;
}
Err(e) => {
warn!("Failed to query for {}: {:?}", parent_block_id, &e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this doesn't work for Stacks 2.x replay?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently yes, but I would like to cover pre-nakamoto too

return None;
}
}

let dbconfig = self.config();

let conn = self.clarity_state.begin_simulated_block(
parent_block_id,
new_block_id,
&self.state_index,
burn_dbconn,
);

let mut clarity_tx = ClarityTx {
block: conn,
config: dbconfig,
};
let result = to_do(&mut clarity_tx);
clarity_tx.rollback_block();
Some(result)
}

/// Run to_do on the state of the Clarity VM at the given chain tip.
/// Returns Some(x: R) if the given parent_tip exists.
/// Returns None if not
Expand Down
20 changes: 20 additions & 0 deletions stackslib/src/chainstate/stacks/index/marf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,26 @@ impl<'a, T: MarfTrieId> MarfTransaction<'a, T> {
self.inner_setup_extension(chain_tip, next_chain_tip, block_height, true)
}

pub fn begin_simulated(&mut self, chain_tip: &T, next_chain_tip: &T) -> Result<(), Error> {
if self.storage.readonly() {
return Err(Error::ReadOnlyError);
}
if self.open_chain_tip.is_some() {
return Err(Error::InProgressError);
}

self.storage.hide_block(next_chain_tip)?;

if self.storage.has_block(next_chain_tip)? {
error!("Block data already exists: {}", next_chain_tip);
return Err(Error::ExistsError);
}

let block_height = self.inner_get_extension_height(chain_tip, next_chain_tip)?;
MARF::extend_trie(&mut self.storage, next_chain_tip)?;
self.inner_setup_extension(chain_tip, next_chain_tip, block_height, true)
}

/// Set up the trie extension we're making.
/// Sets storage pointer to chain_tip.
/// Returns the height next_chain_tip would be at.
Expand Down
7 changes: 7 additions & 0 deletions stackslib/src/chainstate/stacks/index/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2169,6 +2169,13 @@ impl<T: MarfTrieId> TrieStorageConnection<'_, T> {
}
}

pub fn hide_block(&self, bhh: &T) -> Result<bool, Error> {
match trie_sql::hide_block(&self.db, bhh) {
Ok(_) => Ok(true),
Err(e) => Err(e),
}
}

/// Is the given block in the marf_data DB table, and is it unconfirmed?
pub fn has_unconfirmed_block(&self, bhh: &T) -> Result<bool, Error> {
match trie_sql::get_unconfirmed_block_identifier(&self.db, bhh) {
Expand Down
9 changes: 9 additions & 0 deletions stackslib/src/chainstate/stacks/index/trie_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ pub fn get_block_hash<T: MarfTrieId>(conn: &Connection, local_id: u32) -> Result
}

/// Write a serialized trie to sqlite
pub fn hide_block<T: MarfTrieId>(conn: &Connection, block_hash: &T) -> Result<(), Error> {
let args = params![block_hash];
let mut s = conn.prepare("DELETE FROM marf_data WHERE block_hash = ?")?;
s.execute(args)?;
let mut s = conn.prepare("DELETE FROM metadata_table WHERE blockhash = ?")?;
s.execute(args)?;
Ok(())
}

pub fn write_trie_blob<T: MarfTrieId>(
conn: &Connection,
block_hash: &T,
Expand Down
35 changes: 35 additions & 0 deletions stackslib/src/clarity_vm/clarity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,41 @@ impl ClarityInstance {
}
}

pub fn begin_simulated_block<'a, 'b>(
&'a mut self,
current: &StacksBlockId,
next: &StacksBlockId,
header_db: &'b dyn HeadersDB,
burn_state_db: &'b dyn BurnStateDB,
) -> ClarityBlockConnection<'a, 'b> {
let mut datastore = self.datastore.begin_simulated(current, next);

let epoch = Self::get_epoch_of(current, header_db, burn_state_db);
let cost_track = {
let mut clarity_db = datastore.as_clarity_db(&NULL_HEADER_DB, &NULL_BURN_STATE_DB);
Some(
LimitedCostTracker::new(
self.mainnet,
self.chain_id,
epoch.block_limit.clone(),
&mut clarity_db,
epoch.epoch_id,
)
.expect("FAIL: problem instantiating cost tracking"),
)
};

ClarityBlockConnection {
datastore,
header_db,
burn_state_db,
cost_track,
mainnet: self.mainnet,
chain_id: self.chain_id,
epoch: epoch.epoch_id,
}
}

pub fn begin_genesis_block<'a, 'b>(
&'a mut self,
current: &StacksBlockId,
Expand Down
29 changes: 29 additions & 0 deletions stackslib/src/clarity_vm/database/marf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,35 @@ impl MarfedKV {
}
}

pub fn begin_simulated<'a>(
&'a mut self,
current: &StacksBlockId,
next: &StacksBlockId,
) -> WritableMarfStore<'a> {
let mut tx = self.marf.begin_tx().unwrap_or_else(|_| {
panic!(
"ERROR: Failed to begin new MARF block {} - {})",
current, next
)
});
tx.begin_simulated(current, next).unwrap_or_else(|e| {
panic!(
"ERROR: Failed to begin new MARF block {} - {} {}",
current, next, e
)
});

let chain_tip = tx
.get_open_chain_tip()
.expect("ERROR: Failed to get open MARF")
.clone();

WritableMarfStore {
chain_tip,
marf: tx,
}
}

pub fn begin_unconfirmed<'a>(&'a mut self, current: &StacksBlockId) -> WritableMarfStore<'a> {
let mut tx = self.marf.begin_tx().unwrap_or_else(|_| {
panic!(
Expand Down
Loading
Loading