瀏覽代碼

drk: contract deployment history added

skoupidi 9 月之前
父節點
當前提交
3d62bd6a2c
共有 7 個文件被更改,包括 342 次插入24 次删除
  1. 17 0
      bin/drk/deploy.sql
  2. 16 6
      bin/drk/src/cli_util.rs
  3. 187 9
      bin/drk/src/deploy.rs
  4. 54 2
      bin/drk/src/interactive.rs
  5. 1 0
      bin/drk/src/lib.rs
  6. 63 7
      bin/drk/src/main.rs
  7. 4 0
      bin/drk/src/scanned_blocks.rs

+ 17 - 0
bin/drk/deploy.sql

@@ -11,3 +11,20 @@ CREATE TABLE IF NOT EXISTS EJs7oEjKkvCeEVCmpRsd6fEoTGCFJ7WKUBfmAjwaegN_deploy_au
     -- Block height of the transaction this contract was locked on chain
     lock_height INTEGER
 );
+
+CREATE TABLE IF NOT EXISTS EJs7oEjKkvCeEVCmpRsd6fEoTGCFJ7WKUBfmAjwaegN_deploy_history (
+    -- Transaction hash where this deployment action was executed
+    tx_hash TEXT PRIMARY KEY NOT NULL,
+    -- Authority identifier this deployment action is for
+    contract BLOB NOT NULL,
+    -- Type of this deployment action
+    type TEXT NOT NULL,
+    -- Block height of the transaction this deployment action was executed
+    block_height INTEGER NOT NULL,
+    -- Deployed WASM bincode of a deploy type action
+    wasm_bincode BLOB,
+    -- Serialized deploy instruction of a deploy type action
+    deploy_ix BLOB,
+
+    FOREIGN KEY(contract) REFERENCES EJs7oEjKkvCeEVCmpRsd6fEoTGCFJ7WKUBfmAjwaegN_deploy_auth(contract_id) ON DELETE CASCADE ON UPDATE CASCADE
+);

+ 16 - 6
bin/drk/src/cli_util.rs

@@ -180,7 +180,7 @@ pub fn generate_completions(shell: &str) -> Result<String> {
         .about("Read a transaction from stdin and mark its input coins as spent");
 
     // Unspend
-    let coin = Arg::with_name("coin").help("base58-encoded coin to mark as unspent");
+    let coin = Arg::with_name("coin").help("base64-encoded coin to mark as unspent");
 
     let unspend = SubCommand::with_name("unspend").about("Unspend a coin").arg(coin);
 
@@ -338,7 +338,7 @@ pub fn generate_completions(shell: &str) -> Result<String> {
         SubCommand::with_name("exec").about("Execute a DAO proposal").args(&vec![bulla, early]);
 
     let spend_hook_cmd = SubCommand::with_name("spend-hook")
-        .about("Print the DAO contract base58-encoded spend hook");
+        .about("Print the DAO contract base64-encoded spend hook");
 
     let dao = SubCommand::with_name("dao").about("DAO functionalities").subcommands(vec![
         create,
@@ -381,7 +381,7 @@ pub fn generate_completions(shell: &str) -> Result<String> {
     // Explorer
     let tx_hash = Arg::with_name("tx-hash").help("Transaction hash");
 
-    let encode = Arg::with_name("encode").long("encode").help("Encode transaction to base58");
+    let encode = Arg::with_name("encode").long("encode").help("Encode transaction to base64");
 
     let fetch_tx = SubCommand::with_name("fetch-tx")
         .about("Fetch a blockchain transaction by hash")
@@ -394,7 +394,7 @@ pub fn generate_completions(shell: &str) -> Result<String> {
 
     let encode = Arg::with_name("encode")
         .long("encode")
-        .help("Encode specific history record transaction to base58");
+        .help("Encode specific history record transaction to base64");
 
     let txs_history = SubCommand::with_name("txs-history")
         .about("Fetch broadcasted transactions history")
@@ -488,7 +488,17 @@ pub fn generate_completions(shell: &str) -> Result<String> {
     let generate_deploy =
         SubCommand::with_name("generate-deploy").about("Generate a new deploy authority");
 
-    let list = SubCommand::with_name("list").about("List deploy authorities in the wallet");
+    let contract_id = Arg::with_name("contract-id").help("Contract ID (optional)");
+
+    let list = SubCommand::with_name("list")
+        .about("List deploy authorities in the wallet (or a specific one)")
+        .args(&vec![contract_id]);
+
+    let tx_hash = Arg::with_name("tx-hash").help("Record transaction hash");
+
+    let export_data = SubCommand::with_name("export-data")
+        .about("Export a contract history record wasm bincode and deployment instruction, encoded to base64")
+        .args(&vec![tx_hash]);
 
     let deploy_auth = Arg::with_name("deploy-auth").help("Contract ID (deploy authority)");
 
@@ -508,7 +518,7 @@ pub fn generate_completions(shell: &str) -> Result<String> {
 
     let contract = SubCommand::with_name("contract")
         .about("Contract functionalities")
-        .subcommands(vec![generate_deploy, list, deploy, lock]);
+        .subcommands(vec![generate_deploy, list, export_data, deploy, lock]);
 
     // Main arguments
     let config = Arg::with_name("config")

+ 187 - 9
bin/drk/src/deploy.rs

@@ -41,7 +41,7 @@ use darkfi_sdk::{
     tx::TransactionHash,
     ContractCall,
 };
-use darkfi_serial::{deserialize_async, serialize_async, AsyncEncodable};
+use darkfi_serial::{deserialize_async, serialize, serialize_async, AsyncEncodable};
 use rusqlite::types::Value;
 
 use crate::{convert_named_params, error::WalletDbResult, rpc::ScanCache, Drk};
@@ -51,6 +51,8 @@ use crate::{convert_named_params, error::WalletDbResult, rpc::ScanCache, Drk};
 lazy_static! {
     pub static ref DEPLOY_AUTH_TABLE: String =
         format!("{}_deploy_auth", DEPLOYOOOR_CONTRACT_ID.to_string());
+    pub static ref DEPLOY_HISTORY_TABLE: String =
+        format!("{}_deploy_history", DEPLOYOOOR_CONTRACT_ID.to_string());
 }
 
 // DEPLOY_AUTH_TABLE
@@ -59,6 +61,14 @@ pub const DEPLOY_AUTH_COL_SECRET_KEY: &str = "secret_key";
 pub const DEPLOY_AUTH_COL_IS_LOCKED: &str = "is_locked";
 pub const DEPLOY_AUTH_COL_LOCK_HEIGHT: &str = "lock_height";
 
+// DEPLOY_HISTORY_TABLE
+pub const DEPLOY_HISTORY_COL_TX_HASH: &str = "tx_hash";
+pub const DEPLOY_HISTORY_COL_CONTRACT: &str = "contract";
+pub const DEPLOY_HISTORY_COL_TYPE: &str = "type";
+pub const DEPLOY_HISTORY_COL_BLOCK_HEIGHT: &str = "block_height";
+pub const DEPLOY_HISTORY_COL_WASM_BINCODE: &str = "wasm_bincode";
+pub const DEPLOY_HISTORY_COL_DEPLOY_IX: &str = "deploy_ix";
+
 impl Drk {
     /// Initialize wallet with tables for the Deployooor contract.
     pub fn initialize_deployooor(&self) -> WalletDbResult<()> {
@@ -101,7 +111,42 @@ impl Drk {
         Ok(())
     }
 
-    /// Reset all token deploy authorities locked status in the wallet.
+    /// Insert a deploy authority history record into the wallet.
+    pub fn put_deploy_history_record(
+        &self,
+        tx_hash: &TransactionHash,
+        contract: &ContractId,
+        tx_type: &str,
+        block_height: &u32,
+        wasm_bincode: &Option<Vec<u8>>,
+        deploy_ix: &Option<Vec<u8>>,
+    ) -> WalletDbResult<()> {
+        let query = format!(
+            "INSERT INTO {} ({}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6);",
+            *DEPLOY_HISTORY_TABLE,
+            DEPLOY_HISTORY_COL_TX_HASH,
+            DEPLOY_HISTORY_COL_CONTRACT,
+            DEPLOY_HISTORY_COL_TYPE,
+            DEPLOY_HISTORY_COL_BLOCK_HEIGHT,
+            DEPLOY_HISTORY_COL_WASM_BINCODE,
+            DEPLOY_HISTORY_COL_DEPLOY_IX,
+        );
+        self.wallet.exec_sql(
+            &query,
+            rusqlite::params![
+                tx_hash.to_string(),
+                serialize(contract),
+                tx_type,
+                block_height,
+                serialize(wasm_bincode),
+                serialize(deploy_ix),
+            ],
+        )?;
+
+        Ok(())
+    }
+
+    /// Reset all contract deploy authorities locked status in the wallet.
     pub fn reset_deploy_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting deploy authorities locked status"));
         let query = format!(
@@ -135,6 +180,34 @@ impl Drk {
         Ok(())
     }
 
+    /// Reset all contracts history records in the wallet.
+    pub fn reset_deploy_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+        output.push(String::from("Resetting deployment history"));
+        let query = format!("DELETE FROM {};", *DEPLOY_HISTORY_TABLE);
+        self.wallet.exec_sql(&query, &[])?;
+        output.push(String::from("Successfully deployment history"));
+
+        Ok(())
+    }
+
+    /// Remove the contracts history records in the wallet that were
+    /// created after provided height.
+    pub fn remove_deploy_history_after(
+        &self,
+        height: &u32,
+        output: &mut Vec<String>,
+    ) -> WalletDbResult<()> {
+        output.push(format!("Removing deployment history records after: {height}"));
+        let query = format!(
+            "DELETE FROM {} WHERE {} > ?1;",
+            *DEPLOY_HISTORY_TABLE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT
+        );
+        self.wallet.exec_sql(&query, rusqlite::params![height])?;
+        output.push(String::from("Successfully removed deployment history records"));
+
+        Ok(())
+    }
+
     /// List contract deploy authorities from the wallet
     pub async fn list_deploy_auth(
         &self,
@@ -248,6 +321,90 @@ impl Drk {
         Ok(ret)
     }
 
+    /// Retrieve all deploy history records basic information, for
+    /// provided contract id.
+    pub async fn get_deploy_auth_history(
+        &self,
+        contract_id: &ContractId,
+    ) -> Result<Vec<(String, String, u32)>> {
+        let rows = match self.wallet.query_multiple(
+            &DEPLOY_HISTORY_TABLE,
+            &[DEPLOY_HISTORY_COL_TX_HASH, DEPLOY_HISTORY_COL_TYPE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT],
+            convert_named_params! {(DEPLOY_HISTORY_COL_CONTRACT, serialize_async(contract_id).await)},
+        ) {
+            Ok(r) => r,
+            Err(e) => {
+                return Err(Error::DatabaseError(format!(
+                "[get_deploy_auth_history] Failed to retrieve deploy authority history records: {e}",
+            )))
+            }
+        };
+
+        let mut ret = Vec::with_capacity(rows.len());
+        for row in rows {
+            let Value::Text(ref tx_hash) = row[0] else {
+                return Err(Error::ParseFailed(
+                    "[get_deploy_auth_history] Transaction hash parsing failed",
+                ))
+            };
+
+            let Value::Text(ref tx_type) = row[1] else {
+                return Err(Error::ParseFailed("[get_deploy_auth_history] Type parsing failed"))
+            };
+
+            let Value::Integer(block_height) = row[2] else {
+                return Err(Error::ParseFailed(
+                    "[get_deploy_auth_history] Block height parsing failed",
+                ))
+            };
+            let Ok(block_height) = u32::try_from(block_height) else {
+                return Err(Error::ParseFailed(
+                    "[get_deploy_auth_history] Block height parsing failed",
+                ))
+            };
+
+            ret.push((tx_hash.clone(), tx_type.clone(), block_height));
+        }
+
+        Ok(ret)
+    }
+
+    /// Retrieve deploy history record WASM bincode and deployed
+    /// instruction, for provided transaction hash.
+    pub async fn get_deploy_history_record_data(
+        &self,
+        tx_hash: &str,
+    ) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
+        let row = match self.wallet.query_single(
+            &DEPLOY_HISTORY_TABLE,
+            &[DEPLOY_HISTORY_COL_WASM_BINCODE, DEPLOY_HISTORY_COL_DEPLOY_IX],
+            convert_named_params! {(DEPLOY_HISTORY_COL_TX_HASH, tx_hash)},
+        ) {
+            Ok(v) => v,
+            Err(e) => {
+                return Err(Error::DatabaseError(format!(
+                    "[get_deploy_history_record] Failed to retrieve deploy history record: {e}"
+                )))
+            }
+        };
+
+        let Value::Blob(ref wasm_bincode_bytes) = row[0] else {
+            return Err(Error::ParseFailed(
+                "[get_deploy_history_record] Failed to parse wasm bincode bytes",
+            ))
+        };
+        let wasm_bincode: Option<Vec<u8>> = deserialize_async(wasm_bincode_bytes).await?;
+
+        let Value::Blob(ref deploy_ix_bytes) = row[1] else {
+            return Err(Error::ParseFailed(
+                "[get_deploy_history_record] Failed to parse deploy ix bytes",
+            ))
+        };
+        let deploy_ix: Option<Vec<u8>> = deserialize_async(deploy_ix_bytes).await?;
+
+        Ok((wasm_bincode, deploy_ix))
+    }
+
     /// Auxiliary function to apply `DeployFunction::DeployV1` call
     /// data to the wallet.
     /// Returns a flag indicating if the provided call refers to our
@@ -256,17 +413,27 @@ impl Drk {
         &self,
         scan_cache: &ScanCache,
         params: &DeployParamsV1,
-        _tx_hash: &TransactionHash,
-        _block_height: &u32,
+        tx_hash: &TransactionHash,
+        block_height: &u32,
     ) -> Result<bool> {
         // Check if we have the deploy authority key
-        let Some(_secret_key) = scan_cache.own_deploy_auths.get(&params.public_key.to_bytes())
-        else {
+        let Some(_) = scan_cache.own_deploy_auths.get(&params.public_key.to_bytes()) else {
             return Ok(false)
         };
 
         // Create a new history record containing the deployment data
-        // TODO
+        if let Err(e) = self.put_deploy_history_record(
+            tx_hash,
+            &ContractId::derive_public(params.public_key),
+            "DEPLOYMENT",
+            block_height,
+            &Some(params.wasm_bincode.clone()),
+            &Some(params.ix.clone()),
+        ) {
+            return Err(Error::DatabaseError(format!(
+                "[apply_deploy_deploy_data] Inserting deploy history recod failed: {e}"
+            )))
+        }
 
         Ok(true)
     }
@@ -279,7 +446,7 @@ impl Drk {
         &self,
         scan_cache: &ScanCache,
         public_key: &PublicKey,
-        _tx_hash: &TransactionHash,
+        tx_hash: &TransactionHash,
         lock_height: &u32,
     ) -> Result<bool> {
         // Check if we have the deploy authority key
@@ -305,7 +472,18 @@ impl Drk {
         }
 
         // Create a new history record for the lock transaction
-        // TODO
+        if let Err(e) = self.put_deploy_history_record(
+            tx_hash,
+            &ContractId::derive_public(*public_key),
+            "LOCK",
+            lock_height,
+            &None,
+            &None,
+        ) {
+            return Err(Error::DatabaseError(format!(
+                "[apply_deploy_lock_data] Inserting deploy history recod failed: {e}"
+            )))
+        }
 
         Ok(true)
     }

+ 54 - 2
bin/drk/src/interactive.rs

@@ -291,6 +291,7 @@ fn completion(buffer: &str, lc: &mut Vec<String>) {
         lc.push(prefix.clone() + "contract");
         lc.push(prefix.clone() + "contract generate-deploy");
         lc.push(prefix.clone() + "contract list");
+        lc.push(prefix.clone() + "contract export-data");
         lc.push(prefix.clone() + "contract deploy");
         lc.push(prefix + "contract lock");
         return
@@ -365,6 +366,8 @@ fn hints(buffer: &str) -> Option<(String, i32, bool)> {
         "token mint " => Some(("<token> <amount> <recipient> [spend-hook] [user-data]".to_string(), color, bold)),
         "token freeze " => Some(("<token>".to_string(), color, bold)),
         "contract " => Some(("(generate-deploy|list|deploy|lock)".to_string(), color, bold)),
+        "contract list " => Some(("[contract-id]".to_string(), color, bold)),
+        "contract export-data " => Some(("<tx-hash>".to_string(), color, bold)),
         "contract deploy " => Some(("<deploy-auth> <wasm-path> [deploy-ix]".to_string(), color, bold)),
         "contract lock " => Some(("<deploy-auth>".to_string(), color, bold)),
         _ => None,
@@ -3082,6 +3085,7 @@ async fn handle_contract(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>)
     match parts[1] {
         "generate-deploy" => handle_contract_generate_deploy(drk, parts, output).await,
         "list" => handle_contract_list(drk, parts, output).await,
+        "export-data" => handle_contract_export_data(drk, parts, output).await,
         "deploy" => handle_contract_deploy(drk, parts, output).await,
         "lock" => handle_contract_lock(drk, parts, output).await,
         _ => {
@@ -3108,9 +3112,42 @@ async fn handle_contract_generate_deploy(drk: &DrkPtr, parts: &[&str], output: &
 /// Auxiliary function to define the contract list subcommand handling.
 async fn handle_contract_list(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
     // Check correct subcommand structure
-    if parts.len() != 2 {
+    if parts.len() != 2 || parts.len() != 3 {
         output.push(String::from("Malformed `contract list` subcommand"));
-        output.push(String::from("Usage: contract list"));
+        output.push(String::from("Usage: contract list [contract-id]"));
+        return
+    }
+
+    if parts.len() == 3 {
+        let deploy_auth = match ContractId::from_str(parts[2]) {
+            Ok(d) => d,
+            Err(e) => {
+                output.push(format!("Invalid deploy authority: {e}"));
+                return
+            }
+        };
+
+        let history = match drk.read().await.get_deploy_auth_history(&deploy_auth).await {
+            Ok(a) => a,
+            Err(e) => {
+                output.push(format!("Failed to fetch deploy authority history records: {e}"));
+                return
+            }
+        };
+
+        let mut table = Table::new();
+        table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
+        table.set_titles(row!["Transaction Hash", "Type", "Block Height"]);
+
+        for (tx_hash, tx_type, block_height) in history {
+            table.add_row(row![tx_hash, tx_type, block_height]);
+        }
+
+        if table.is_empty() {
+            output.push(String::from("No history records found"));
+        } else {
+            output.push(format!("{table}"));
+        }
         return
     }
 
@@ -3141,6 +3178,21 @@ async fn handle_contract_list(drk: &DrkPtr, parts: &[&str], output: &mut Vec<Str
     }
 }
 
+/// Auxiliary function to define the contract export data subcommand handling.
+async fn handle_contract_export_data(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
+    // Check correct subcommand structure
+    if parts.len() != 3 {
+        output.push(String::from("Malformed `contract export-data` subcommand"));
+        output.push(String::from("Usage: contract export-data <tx-hash>"));
+        return
+    }
+
+    match drk.read().await.get_deploy_history_record_data(parts[2]).await {
+        Ok(pair) => output.push(base64::encode(&serialize_async(&pair).await)),
+        Err(e) => output.push(format!("Failed to retrieve history record: {e}")),
+    }
+}
+
 /// Auxiliary function to define the contract deploy subcommand handling.
 async fn handle_contract_deploy(drk: &DrkPtr, parts: &[&str], output: &mut Vec<String>) {
     // Check correct subcommand structure

+ 1 - 0
bin/drk/src/lib.rs

@@ -145,6 +145,7 @@ impl Drk {
         self.reset_dao_proposals(output)?;
         self.reset_dao_votes(output)?;
         self.reset_deploy_authorities(output)?;
+        self.reset_deploy_history(output)?;
         self.reset_tx_history(output)?;
         output.push(String::from("Successfully reset full wallet state"));
         Ok(())

+ 63 - 7
bin/drk/src/main.rs

@@ -130,7 +130,7 @@ enum Subcmd {
 
     /// Unspend a coin
     Unspend {
-        /// base58-encoded coin to mark as unspent
+        /// base64-encoded coin to mark as unspent
         coin: String,
     },
 
@@ -403,7 +403,7 @@ enum DaoSubcmd {
         early: bool,
     },
 
-    /// Print the DAO contract base58-encoded spend hook
+    /// Print the DAO contract base64-encoded spend hook
     SpendHook,
 }
 
@@ -415,7 +415,7 @@ enum ExplorerSubcmd {
         tx_hash: String,
 
         #[structopt(long)]
-        /// Encode transaction to base58
+        /// Encode transaction to base64
         encode: bool,
     },
 
@@ -428,7 +428,7 @@ enum ExplorerSubcmd {
         tx_hash: Option<String>,
 
         #[structopt(long)]
-        /// Encode specific history record transaction to base58
+        /// Encode specific history record transaction to base64
         encode: bool,
     },
 
@@ -519,8 +519,17 @@ enum ContractSubcmd {
     /// Generate a new deploy authority
     GenerateDeploy,
 
-    /// List deploy authorities in the wallet
-    List,
+    /// List deploy authorities in the wallet (or a specific one)
+    List {
+        /// Contract ID (optional)
+        contract_id: Option<String>,
+    },
+
+    /// Export a contract history record wasm bincode and deployment instruction, encoded to base64
+    ExportData {
+        /// Record transaction hash
+        tx_hash: String,
+    },
 
     /// Deploy a smart contract
     Deploy {
@@ -2571,7 +2580,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 Ok(())
             }
 
-            ContractSubcmd::List => {
+            ContractSubcmd::List { contract_id } => {
                 let drk = new_wallet(
                     blockchain_config.cache_path,
                     blockchain_config.wallet_path,
@@ -2581,6 +2590,35 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                     args.fun,
                 )
                 .await;
+
+                if let Some(contract_id) = contract_id {
+                    let contract_id = match ContractId::from_str(&contract_id) {
+                        Ok(d) => d,
+                        Err(e) => {
+                            eprintln!("Invalid contract id: {e}");
+                            exit(2);
+                        }
+                    };
+
+                    let history = drk.get_deploy_auth_history(&contract_id).await?;
+
+                    let mut table = Table::new();
+                    table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
+                    table.set_titles(row!["Transaction Hash", "Type", "Block Height"]);
+
+                    for (tx_hash, tx_type, block_height) in history {
+                        table.add_row(row![tx_hash, tx_type, block_height]);
+                    }
+
+                    if table.is_empty() {
+                        println!("No history records found");
+                    } else {
+                        println!("{table}");
+                    }
+
+                    return Ok(())
+                }
+
                 let auths = drk.list_deploy_auth().await?;
 
                 let mut table = Table::new();
@@ -2604,6 +2642,24 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 Ok(())
             }
 
+            ContractSubcmd::ExportData { tx_hash } => {
+                let drk = new_wallet(
+                    blockchain_config.cache_path,
+                    blockchain_config.wallet_path,
+                    blockchain_config.wallet_pass,
+                    None,
+                    &ex,
+                    args.fun,
+                )
+                .await;
+
+                let pair = drk.get_deploy_history_record_data(&tx_hash).await?;
+
+                println!("{}", base64::encode(&serialize_async(&pair).await));
+
+                Ok(())
+            }
+
             ContractSubcmd::Deploy { deploy_auth, wasm_path, deploy_ix } => {
                 // Parse the deployment authority contract id
                 let deploy_auth = match ContractId::from_str(&deploy_auth) {

+ 4 - 0
bin/drk/src/scanned_blocks.rs

@@ -229,6 +229,10 @@ impl Drk {
         // Unlock all contracts frozen after the reset height
         self.unlock_deploy_authorities_after(&height, output)?;
 
+        // Remove all contracts history records created after the reset
+        // height.
+        self.remove_deploy_history_after(&height, output)?;
+
         // Set reverted status to all transactions executed after reset
         // height.
         self.revert_transactions_after(&height, output)?;