Repository: NomicFoundation/hardhat-ignition
Pull request #565 (2023-10-16 22:26:59)

fix: rerun deploying panel display (PR A)
Our display of the deployment starting panel is dependent on the `RUN_START` event. Previously this event is triggered only once for a deployment on initialization of the deployment state on the very first run of the deployment. At the least this is a misnomer.

Several moves have been made here:

1. The UI only event DEPLOYMENT_START now occurs at the start of a deploy for both fresh runs and reruns.
2. The `RUN_START` event now occurs at the start of `executeModule` in the execution engine. So there is a `RUN_START` message in the journal for each run.
3. The execution engine is no longer invoked if there are no batches to run (i.e. no uncompleted futures). This means no `RUN_START` event if nothing is executed.
4. The `RUN_START` event no longer clears the previous execution states (a bug that was masked by it only ever being run once in the previous version).

An integration test has been added to pin the `RUN_START` event behaviour of not wiping previous run history.

These changes gives us the correct UI combinations:

- Show Deploying on fresh deploy
- Only show complete on rerun with no new futures
- Show deploying on rerun with new futures

Fixes https://github.com/NomicFoundation/hardhat-ignition/issues/566.

## Preview

Now on the second run with a new contract `AnotherContract` we see the Ignition panel:

![image](https://github.com/NomicFoundation/hardhat-ignition/assets/24030/2a8b7b6f-4510-4307-9d28-0e6fca7c1d15)

And on a rerun with no new futures we see:

![image](https://github.com/NomicFoundation/hardhat-ignition/assets/24030/981f2a8b-ea1c-4dff-8a77-77aebb5fa0d1)


kanej: @alcuadrado there are two considerations here I think.

The first is whether we want a new run event on every run in the journal. I think recording an entry for a new run makes sense, though perhaps adding a timestamp would be the way to go. An alternative though would be to rename the journalable event from `RUN_START` to `DEPLOYMENT_INIT`, then instead of having a `RUN_START` at the beginning of execution phase, we put in a UI only event, and use that for the cli UI ignition running display.

The second issue, is that there is a duplicate call to get chainId. The first is to do the check that we haven't changed the chainId. The second is in the execution engine to record the start of the run (the chainId is needed for that). We could do the chainId call once at the start of deploy and pass  the information down (reworking the execution engine signature).


alcuadrado: I think we should not touch the journal if not necessary. Imagine having the journal in git, and having to commit or reset the file on every run. That'd be unnecessarily annoying.
alcuadrado: Execution events are different from the journal messages. They normally match, but they don't have to.

IMO the correct approach would be emitting an execution event on every run, but not recording a journal message.
alcuadrado: 
> An alternative though would be to rename the journalable event from `RUN_START` to `DEPLOYMENT_INIT`, then instead of having a `RUN_START` at the beginning of execution phase, we put in a UI only event, and use that for the cli UI ignition running display.

Yes, let's do this instead.

> The second issue, is that there is a duplicate call to get chainId. The first is to do the check that we haven't changed the chainId. The second is in the execution engine to record the start of the run (the chainId is needed for that). We could do the chainId call once at the start of deploy and pass the information down (reworking the execution engine signature).

I'm not worried about that duplicated call. I'm pretty sure hardhat caches that info.

Patch:
diff --git a/packages/core/src/internal/deployer.ts b/packages/core/src/internal/deployer.ts
index 5c128ffa..bc95cfb4 100644
--- a/packages/core/src/internal/deployer.ts
+++ b/packages/core/src/internal/deployer.ts
@@ -74,10 +74,9 @@ export class Deployer {
     accounts: string[],
     defaultSender: string
   ): Promise<DeploymentResult> {
-    let deploymentState = await this._getOrInitializeDeploymentState(
-      ignitionModule.id,
-      this._deploymentDir
-    );
+    this._emitDeploymentStartEvent(ignitionModule.id, this._deploymentDir);
+
+    let deploymentState = await this._getOrInitializeDeploymentState();
 
     const contracts =
       getFuturesFromModule(ignitionModule).filter(isContractFuture);
@@ -167,26 +166,30 @@ export class Deployer {
 
     this._emitDeploymentBatchEvent(batches);
 
-    const executionEngine = new ExecutionEngine(
-      this._deploymentLoader,
-      this._artifactResolver,
-      this._executionStrategy,
-      this._jsonRpcClient,
-      this._executionEventListener,
-      this._config.requiredConfirmations,
-      this._config.timeBeforeBumpingFees,
-      this._config.maxFeeBumps,
-      this._config.blockPollingInterval
-    );
+    if (this._hasBatchesToExecute(batches)) {
+      this._emitRunStartEvent();
+
+      const executionEngine = new ExecutionEngine(
+        this._deploymentLoader,
+        this._artifactResolver,
+        this._executionStrategy,
+        this._jsonRpcClient,
+        this._executionEventListener,
+        this._config.requiredConfirmations,
+        this._config.timeBeforeBumpingFees,
+        this._config.maxFeeBumps,
+        this._config.blockPollingInterval
+      );
 
-    deploymentState = await executionEngine.executeModule(
-      deploymentState,
-      ignitionModule,
-      batches,
-      accounts,
-      deploymentParameters,
-      defaultSender
-    );
+      deploymentState = await executionEngine.executeModule(
+        deploymentState,
+        ignitionModule,
+        batches,
+        accounts,
+        deploymentParameters,
+        defaultSender
+      );
+    }
 
     const result = await this._getDeploymentResult(
       deploymentState,
@@ -218,16 +221,11 @@ export class Deployer {
     };
   }
 
-  private async _getOrInitializeDeploymentState(
-    moduleId: string,
-    deploymentDir: string | undefined
-  ): Promise<DeploymentState> {
+  private async _getOrInitializeDeploymentState(): Promise<DeploymentState> {
     const chainId = await this._jsonRpcClient.getChainId();
     const deploymentState = await loadDeploymentState(this._deploymentLoader);
 
     if (deploymentState === undefined) {
-      this._emitDeploymentStartEvent(moduleId, deploymentDir);
-
       return initializeDeploymentState(chainId, this._deploymentLoader);
     }
 
@@ -276,6 +274,16 @@ export class Deployer {
     });
   }
 
+  private _emitRunStartEvent(): void {
+    if (this._executionEventListener === undefined) {
+      return;
+    }
+
+    this._executionEventListener.runStart({
+      type: ExecutionEventType.RUN_START,
+    });
+  }
+
   private _emitDeploymentCompleteEvent(result: DeploymentResult): void {
     if (this._executionEventListener === undefined) {
       return;
@@ -303,4 +311,14 @@ export class Deployer {
       ...status,
     };
   }
+
+  /**
+   * Determine if an execution run is necessary.
+   *
+   * @param batches - the batches to be executed
+   * @returns if there are batches to be executed
+   */
+  private _hasBatchesToExecute(batches: string[][]) {
+    return batches.length > 0;
+  }
 }
diff --git a/packages/core/src/internal/execution/deployment-state-helpers.ts b/packages/core/src/internal/execution/deployment-state-helpers.ts
index 243073d3..4b4fac44 100644
--- a/packages/core/src/internal/execution/deployment-state-helpers.ts
+++ b/packages/core/src/internal/execution/deployment-state-helpers.ts
@@ -4,9 +4,9 @@ import { deploymentStateReducer } from "./reducers/deployment-state-reducer";
 import { DeploymentState } from "./types/deployment-state";
 import { ExecutionResultType } from "./types/execution-result";
 import {
+  DeploymentInitializeMessage,
   JournalMessage,
   JournalMessageType,
-  RunStartMessage,
 } from "./types/messages";
 
 /**
@@ -37,8 +37,8 @@ export async function initializeDeploymentState(
   chainId: number,
   deploymentLoader: DeploymentLoader
 ): Promise<DeploymentState> {
-  const message: RunStartMessage = {
-    type: JournalMessageType.RUN_START,
+  const message: DeploymentInitializeMessage = {
+    type: JournalMessageType.DEPLOYMENT_INITIALIZE,
     chainId,
   };
 
diff --git a/packages/core/src/internal/execution/reducers/deployment-state-reducer.ts b/packages/core/src/internal/execution/reducers/deployment-state-reducer.ts
index 185d38ae..e5e86aac 100644
--- a/packages/core/src/internal/execution/reducers/deployment-state-reducer.ts
+++ b/packages/core/src/internal/execution/reducers/deployment-state-reducer.ts
@@ -26,10 +26,10 @@ export function deploymentStateReducer(
     return state;
   }
 
-  if (action.type === JournalMessageType.RUN_START) {
+  if (action.type === JournalMessageType.DEPLOYMENT_INITIALIZE) {
     return {
+      ...state,
       chainId: action.chainId,
-      executionStates: {},
     };
   }
 
diff --git a/packages/core/src/internal/execution/types/messages.ts b/packages/core/src/internal/execution/types/messages.ts
index c41f9b35..da9b0e15 100644
--- a/packages/core/src/internal/execution/types/messages.ts
+++ b/packages/core/src/internal/execution/types/messages.ts
@@ -18,7 +18,7 @@ import {
 } from "./jsonrpc";
 
 export type JournalMessage =
-  | RunStartMessage
+  | DeploymentInitializeMessage
   | WipeExecutionStateMessage
   | DeploymentExecutionStateInitializeMessage
   | DeploymentExecutionStateCompleteMessage
@@ -46,6 +46,7 @@ export type JournalMessage =
  * be sure to update UiEventType accordingly
  */
 export enum JournalMessageType {
+  DEPLOYMENT_INITIALIZE = "DEPLOYMENT_INITIALIZE",
   RUN_START = "RUN_START",
   WIPE_APPLY = "WIPE_APPLY",
   DEPLOYMENT_EXECUTION_STATE_INITIALIZE = "DEPLOYMENT_EXECUTION_STATE_INITIALIZE",
@@ -68,8 +69,8 @@ export enum JournalMessageType {
   ONCHAIN_INTERACTION_TIMEOUT = "ONCHAIN_INTERACTION_TIMEOUT",
 }
 
-export interface RunStartMessage {
-  type: JournalMessageType.RUN_START;
+export interface DeploymentInitializeMessage {
+  type: JournalMessageType.DEPLOYMENT_INITIALIZE;
   chainId: number;
 }
 
diff --git a/packages/core/src/internal/journal/utils/emitExecutionEvent.ts b/packages/core/src/internal/journal/utils/emitExecutionEvent.ts
index db7c4b12..429d7313 100644
--- a/packages/core/src/internal/journal/utils/emitExecutionEvent.ts
+++ b/packages/core/src/internal/journal/utils/emitExecutionEvent.ts
@@ -26,9 +26,9 @@ export function emitExecutionEvent(
   executionEventListener: ExecutionEventListener
 ): void {
   switch (message.type) {
-    case JournalMessageType.RUN_START: {
-      executionEventListener.runStart({
-        type: ExecutionEventType.RUN_START,
+    case JournalMessageType.DEPLOYMENT_INITIALIZE: {
+      executionEventListener.deploymentInitialize({
+        type: ExecutionEventType.DEPLOYMENT_INITIALIZE,
         chainId: message.chainId,
       });
       break;
diff --git a/packages/core/src/internal/journal/utils/log.ts b/packages/core/src/internal/journal/utils/log.ts
index d5d32b47..3d6660d3 100644
--- a/packages/core/src/internal/journal/utils/log.ts
+++ b/packages/core/src/internal/journal/utils/log.ts
@@ -8,7 +8,7 @@ import { formatSolidityParameter } from "../../formatters";
 
 export function logJournalableMessage(message: JournalMessage): void {
   switch (message.type) {
-    case JournalMessageType.RUN_START:
+    case JournalMessageType.DEPLOYMENT_INITIALIZE:
       console.log(`Deployment started`);
       break;
 
diff --git a/packages/core/src/types/execution-events.ts b/packages/core/src/types/execution-events.ts
index ecc19467..7fb61c06 100644
--- a/packages/core/src/types/execution-events.ts
+++ b/packages/core/src/types/execution-events.ts
@@ -7,7 +7,7 @@ import { DeploymentResult } from "./deploy";
  * @beta
  */
 export type ExecutionEvent =
-  | RunStartEvent
+  | DeploymentInitializeEvent
   | WipeApplyEvent
   | DeploymentExecutionStateInitializeEvent
   | DeploymentExecutionStateCompleteEvent
@@ -39,7 +39,6 @@ export type ExecutionEvent =
  * @beta
  */
 export enum ExecutionEventType {
-  RUN_START = "RUN_START",
   WIPE_APPLY = "WIPE_APPLY",
   DEPLOYMENT_EXECUTION_STATE_INITIALIZE = "DEPLOYMENT_EXECUTION_STATE_INITIALIZE",
   DEPLOYMENT_EXECUTION_STATE_COMPLETE = "DEPLOYMENT_EXECUTION_STATE_COMPLETE",
@@ -59,9 +58,11 @@ export enum ExecutionEventType {
   ONCHAIN_INTERACTION_DROPPED = "ONCHAIN_INTERACTION_DROPPED",
   ONCHAIN_INTERACTION_REPLACED_BY_USER = "ONCHAIN_INTERACTION_REPLACED_BY_USER",
   ONCHAIN_INTERACTION_TIMEOUT = "ONCHAIN_INTERACTION_TIMEOUT",
-  BATCH_INITIALIZE = "BATCH_INITIALIZE",
   DEPLOYMENT_START = "DEPLOYMENT_START",
+  DEPLOYMENT_INITIALIZE = "DEPLOYMENT_INITIALIZE",
   RECONCILIATION_WARNINGS = "RECONCILIATION_WARNINGS",
+  BATCH_INITIALIZE = "BATCH_INITIALIZE",
+  RUN_START = "RUN_START",
   BEGIN_NEXT_BATCH = "BEGIN_NEXT_BATCH",
   DEPLOYMENT_COMPLETE = "DEPLOYMENT_COMPLETE",
   SET_MODULE_ID = "SET_MODULE_ID",
@@ -79,12 +80,12 @@ export interface DeploymentStartEvent {
 }
 
 /**
- * An event indicating a new run has started.
+ * An event indicating a new deployment has been initialized.
  *
  * @beta
  */
-export interface RunStartEvent {
-  type: ExecutionEventType.RUN_START;
+export interface DeploymentInitializeEvent {
+  type: ExecutionEventType.DEPLOYMENT_INITIALIZE;
   chainId: number;
 }
 
@@ -98,6 +99,15 @@ export interface BatchInitializeEvent {
   batches: string[][];
 }
 
+/**
+ * An event indicating that the deployment is commenencing an execution run.
+ *
+ * @beta
+ */
+export interface RunStartEvent {
+  type: ExecutionEventType.RUN_START;
+}
+
 /**
  * An event indicating that the execution engine has moved onto
  * the next batch.
@@ -422,7 +432,6 @@ export interface ExecutionEventHeld {
  * @beta
  */
 export interface ExecutionEventTypeMap {
-  [ExecutionEventType.RUN_START]: RunStartEvent;
   [ExecutionEventType.WIPE_APPLY]: WipeApplyEvent;
   [ExecutionEventType.DEPLOYMENT_EXECUTION_STATE_INITIALIZE]: DeploymentExecutionStateInitializeEvent;
   [ExecutionEventType.DEPLOYMENT_EXECUTION_STATE_COMPLETE]: DeploymentExecutionStateCompleteEvent;
@@ -442,11 +451,13 @@ export interface ExecutionEventTypeMap {
   [ExecutionEventType.ONCHAIN_INTERACTION_DROPPED]: OnchainInteractionDroppedEvent;
   [ExecutionEventType.ONCHAIN_INTERACTION_REPLACED_BY_USER]: OnchainInteractionReplacedByUserEvent;
   [ExecutionEventType.ONCHAIN_INTERACTION_TIMEOUT]: OnchainInteractionTimeoutEvent;
-  [ExecutionEventType.BATCH_INITIALIZE]: BatchInitializeEvent;
   [ExecutionEventType.DEPLOYMENT_START]: DeploymentStartEvent;
+  [ExecutionEventType.DEPLOYMENT_INITIALIZE]: DeploymentInitializeEvent;
+  [ExecutionEventType.RECONCILIATION_WARNINGS]: ReconciliationWarningsEvent;
+  [ExecutionEventType.BATCH_INITIALIZE]: BatchInitializeEvent;
+  [ExecutionEventType.RUN_START]: RunStartEvent;
   [ExecutionEventType.BEGIN_NEXT_BATCH]: BeginNextBatchEvent;
   [ExecutionEventType.DEPLOYMENT_COMPLETE]: DeploymentCompleteEvent;
-  [ExecutionEventType.RECONCILIATION_WARNINGS]: ReconciliationWarningsEvent;
   [ExecutionEventType.SET_MODULE_ID]: SetModuleIdEvent;
 }
 
diff --git a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
index 72e9c5c3..8a1a1c49 100644
--- a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
+++ b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
@@ -7,6 +7,7 @@ import {
   DeploymentCompleteEvent,
   DeploymentExecutionStateCompleteEvent,
   DeploymentExecutionStateInitializeEvent,
+  DeploymentInitializeEvent,
   DeploymentParameters,
   DeploymentResult,
   DeploymentResultType,
@@ -82,12 +83,14 @@ export class PrettyEventHandler implements ExecutionEventListener {
     process.stdout.write(calculateStartingMessage(this.state));
   }
 
-  public runStart(event: RunStartEvent): void {
+  public deploymentInitialize(event: DeploymentInitializeEvent): void {
     this.state = {
       ...this.state,
       chainId: event.chainId,
     };
+  }
 
+  public runStart(_event: RunStartEvent): void {
     this._clearCurrentLine();
     console.log(calculateDeployingModulePanel(this.state));
   }
@@ -249,8 +252,6 @@ export class PrettyEventHandler implements ExecutionEventListener {
   ): void {}
 
   public deploymentComplete(event: DeploymentCompleteEvent): void {
-    const originalStatus = this.state.status;
-
     this.state = {
       ...this.state,
       status: UiStateDeploymentStatus.COMPLETE,
@@ -258,8 +259,13 @@ export class PrettyEventHandler implements ExecutionEventListener {
       batches: this._applyResultToBatches(this.state.batches, event.result),
     };
 
-    if (originalStatus !== UiStateDeploymentStatus.UNSTARTED) {
+    // If batches where executed, rerender the last batch
+    if (this.state.currentBatch > 0) {
       this._redisplayCurrentBatch();
+    } else {
+      // Otherwise only the completion panel will be shown so clear
+      // the Starting Ignition line.
+      this._clearCurrentLine();
     }
 
     console.log(calculateDeploymentCompleteDisplay(event, this.state));
diff --git a/packages/hardhat-plugin/src/ui/verbose-event-handler.ts b/packages/hardhat-plugin/src/ui/verbose-event-handler.ts
index dd93e712..ca340063 100644
--- a/packages/hardhat-plugin/src/ui/verbose-event-handler.ts
+++ b/packages/hardhat-plugin/src/ui/verbose-event-handler.ts
@@ -7,6 +7,7 @@ import {
   DeploymentCompleteEvent,
   DeploymentExecutionStateCompleteEvent,
   DeploymentExecutionStateInitializeEvent,
+  DeploymentInitializeEvent,
   DeploymentStartEvent,
   ExecutionEventListener,
   ExecutionEventNetworkInteractionType,
@@ -29,29 +30,20 @@ import {
   TransactionSendEvent,
   WipeApplyEvent,
 } from "@nomicfoundation/ignition-core";
-import chalk from "chalk";
 
 export class VerboseEventHandler implements ExecutionEventListener {
-  public runStart(event: RunStartEvent): void {
-    console.log(
-      chalk.inverse(`Deployment started for chainId: ${event.chainId}`)
-    );
+  public deploymentInitialize(event: DeploymentInitializeEvent): void {
+    console.log(`Deployment initialized for chainId: ${event.chainId}`);
   }
 
   public wipeApply(event: WipeApplyEvent): void {
-    console.log(
-      chalk.bold(`Removing the execution of future ${event.futureId}`)
-    );
+    console.log(`Removing the execution of future ${event.futureId}`);
   }
 
   public deploymentExecutionStateInitialize(
     event: DeploymentExecutionStateInitializeEvent
   ): void {
-    console.log(
-      chalk.blueBright(
-        `Starting to execute the deployment future ${event.futureId}`
-      )
-    );
+    console.log(`Starting to execute the deployment future ${event.futureId}`);
   }
 
   public deploymentExecutionStateComplete(
@@ -60,25 +52,19 @@ export class VerboseEventHandler implements ExecutionEventListener {
     switch (event.result.type) {
       case ExecutionEventResultType.SUCCESS: {
         return console.log(
-          chalk.bgBlue.bold(
-            `Successfully completed the execution of deployment future ${
-              event.futureId
-            } with address ${event.result.result ?? "undefined"}`
-          )
+          `Successfully completed the execution of deployment future ${
+            event.futureId
+          } with address ${event.result.result ?? "undefined"}`
         );
       }
       case ExecutionEventResultType.ERROR: {
         return console.log(
-          chalk.bgRed.bold(
-            `Execution of future ${event.futureId} failed with reason: ${event.result.error}`
-          )
+          `Execution of future ${event.futureId} failed with reason: ${event.result.error}`
         );
       }
       case ExecutionEventResultType.HELD: {
         return console.log(
-          chalk.bgYellow.bold(
-            `Execution of future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
-          )
+          `Execution of future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
         );
       }
     }
@@ -87,9 +73,7 @@ export class VerboseEventHandler implements ExecutionEventListener {
   public callExecutionStateInitialize(
     event: CallExecutionStateInitializeEvent
   ): void {
-    console.log(
-      chalk.cyanBright(`Starting to execute the call future ${event.futureId}`)
-    );
+    console.log(`Starting to execute the call future ${event.futureId}`);
   }
 
   public callExecutionStateComplete(
@@ -98,23 +82,17 @@ export class VerboseEventHandler implements ExecutionEventListener {
     switch (event.result.type) {
       case ExecutionEventResultType.SUCCESS: {
         return console.log(
-          chalk.bgCyan.bold(
-            `Successfully completed the execution of call future ${event.futureId}`
-          )
+          `Successfully completed the execution of call future ${event.futureId}`
         );
       }
       case ExecutionEventResultType.ERROR: {
         return console.log(
-          chalk.bgRed.bold(
-            `Execution of call future ${event.futureId} failed with reason: ${event.result.error}`
-          )
+          `Execution of call future ${event.futureId} failed with reason: ${event.result.error}`
         );
       }
       case ExecutionEventResultType.HELD: {
         return console.log(
-          chalk.bgYellow.bold(
-            `Execution of call future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
-          )
+          `Execution of call future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
         );
       }
     }
@@ -123,11 +101,7 @@ export class VerboseEventHandler implements ExecutionEventListener {
   public staticCallExecutionStateInitialize(
     event: StaticCallExecutionStateInitializeEvent
   ): void {
-    console.log(
-      chalk.cyanBright(
-        `Starting to execute the static call future ${event.futureId}`
-      )
-    );
+    console.log(`Starting to execute the static call future ${event.futureId}`);
   }
 
   public staticCallExecutionStateComplete(
@@ -136,25 +110,19 @@ export class VerboseEventHandler implements ExecutionEventListener {
     switch (event.result.type) {
       case ExecutionEventResultType.SUCCESS: {
         return console.log(
-          chalk.bgCyan.bold(
-            `Successfully completed the execution of static call future ${
-              event.futureId
-            } with result ${event.result.result ?? "undefined"}`
-          )
+          `Successfully completed the execution of static call future ${
+            event.futureId
+          } with result ${event.result.result ?? "undefined"}`
         );
       }
       case ExecutionEventResultType.ERROR: {
         return console.log(
-          chalk.bgRed.bold(
-            `Execution of static call future ${event.futureId} failed with reason: ${event.result.error}`
-          )
+          `Execution of static call future ${event.futureId} failed with reason: ${event.result.error}`
         );
       }
       case ExecutionEventResultType.HELD: {
         return console.log(
-          chalk.bgYellow.bold(
-            `Execution of static call future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
-          )
+          `Execution of static call future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
         );
       }
     }
@@ -163,11 +131,7 @@ export class VerboseEventHandler implements ExecutionEventListener {
   public sendDataExecutionStateInitialize(
     event: SendDataExecutionStateInitializeEvent
   ): void {
-    console.log(
-      chalk.magentaBright(
-        `Started to execute the send data future ${event.futureId}`
-      )
-    );
+    console.log(`Started to execute the send data future ${event.futureId}`);
   }
 
   public sendDataExecutionStateComplete(
@@ -176,25 +140,19 @@ export class VerboseEventHandler implements ExecutionEventListener {
     switch (event.result.type) {
       case ExecutionEventResultType.SUCCESS: {
         return console.log(
-          chalk.bgMagenta.bold(
-            `Successfully completed the execution of send data future ${
-              event.futureId
-            } in tx ${event.result.result ?? "undefined"}`
-          )
+          `Successfully completed the execution of send data future ${
+            event.futureId
+          } in tx ${event.result.result ?? "undefined"}`
         );
       }
       case ExecutionEventResultType.ERROR: {
         return console.log(
-          chalk.bgRed.bold(
-            `Execution of future ${event.futureId} failed with reason: ${event.result.error}`
-          )
+          `Execution of future ${event.futureId} failed with reason: ${event.result.error}`
         );
       }
       case ExecutionEventResultType.HELD: {
         return console.log(
-          chalk.bgYellow.bold(
-            `Execution of send future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
-          )
+          `Execution of send future ${event.futureId}/${event.result.heldId} held with reason: ${event.result.reason}`
         );
       }
     }
@@ -203,20 +161,16 @@ export class VerboseEventHandler implements ExecutionEventListener {
   public contractAtExecutionStateInitialize(
     event: ContractAtExecutionStateInitializeEvent
   ): void {
-    console.log(
-      chalk.gray.bold(`Executed contract at future ${event.futureId}`)
-    );
+    console.log(`Executed contract at future ${event.futureId}`);
   }
 
   public readEventArgumentExecutionStateInitialize(
     event: ReadEventArgExecutionStateInitializeEvent
   ): void {
     console.log(
-      chalk.green.dim(
-        `Executed read event argument future ${event.futureId} with result ${
-          event.result.result ?? "undefined"
-        }`
-      )
+      `Executed read event argument future ${event.futureId} with result ${
+        event.result.result ?? "undefined"
+      }`
     );
   }
 
@@ -228,42 +182,32 @@ export class VerboseEventHandler implements ExecutionEventListener {
       ExecutionEventNetworkInteractionType.ONCHAIN_INTERACTION
     ) {
       console.log(
-        chalk.dim(
-          `New onchain interaction requested for future ${event.futureId}`
-        )
+        `New onchain interaction requested for future ${event.futureId}`
       );
     } else {
-      console.log(
-        chalk.dim(`New static call requested for future ${event.futureId}`)
-      );
+      console.log(`New static call requested for future ${event.futureId}`);
     }
   }
 
   public transactionSend(event: TransactionSendEvent): void {
     console.log(
-      chalk.dim(
-        `Transaction ${event.hash} sent for onchain interaction of future ${event.futureId}`
-      )
+      `Transaction ${event.hash} sent for onchain interaction of future ${event.futureId}`
     );
   }
 
   public transactionConfirm(event: TransactionConfirmEvent): void {
-    console.log(chalk.dim(`Transaction ${event.hash} confirmed`));
+    console.log(`Transaction ${event.hash} confirmed`);
   }
 
   public staticCallComplete(event: StaticCallCompleteEvent): void {
-    console.log(
-      chalk.dim(`Static call completed for future ${event.futureId}`)
-    );
+    console.log(`Static call completed for future ${event.futureId}`);
   }
 
   public onchainInteractionBumpFees(
     event: OnchainInteractionBumpFeesEvent
   ): void {
     console.log(
-      chalk.dim(
-        `A transaction with higher fees will be sent for onchain interaction of future ${event.futureId}`
-      )
+      `A transaction with higher fees will be sent for onchain interaction of future ${event.futureId}`
     );
   }
 
@@ -271,9 +215,7 @@ export class VerboseEventHandler implements ExecutionEventListener {
     event: OnchainInteractionDroppedEvent
   ): void {
     console.log(
-      chalk.dim(
-        `Transactions for onchain interaction of future ${event.futureId} has been dropped and will be resent`
-      )
+      `Transactions for onchain interaction of future ${event.futureId} has been dropped and will be resent`
     );
   }
 
@@ -281,9 +223,7 @@ export class VerboseEventHandler implements ExecutionEventListener {
     event: OnchainInteractionReplacedByUserEvent
   ): void {
     console.log(
-      chalk.dim(
-        `Transactions for onchain interaction of future ${event.futureId} has been replaced by the user and the onchain interaction exection will start again`
-      )
+      `Transactions for onchain interaction of future ${event.futureId} has been replaced by the user and the onchain interaction exection will start again`
     );
   }
 
@@ -291,32 +231,26 @@ export class VerboseEventHandler implements ExecutionEventListener {
     event: OnchainInteractionTimeoutEvent
   ): void {
     console.log(
-      chalk.dim(
-        `Onchain interaction of future ${event.futureId} failed due to being resent too many times and not having confirmed`
-      )
+      `Onchain interaction of future ${event.futureId} failed due to being resent too many times and not having confirmed`
     );
   }
 
   public batchInitialize(event: BatchInitializeEvent): void {
     console.log(
-      chalk.greenBright.bold(
-        `Starting execution for batches: ${JSON.stringify(event.batches)}`
-      )
+      `Starting execution for batches: ${JSON.stringify(event.batches)}`
     );
   }
 
   public deploymentStart(_event: DeploymentStartEvent): void {
-    console.log(
-      chalk.yellowBright.bold(`Starting execution for new deployment`)
-    );
+    console.log(`Starting execution for new deployment`);
   }
 
   public beginNextBatch(_event: BeginNextBatchEvent): void {
-    console.log(chalk.greenBright.bold(`Starting execution for next batch`));
+    console.log(`Starting execution for next batch`);
   }
 
   public deploymentComplete(_event: DeploymentCompleteEvent): void {
-    console.log(chalk.bgGreen.bold(`Deployment complete`));
+    console.log(`Deployment complete`);
   }
 
   public reconciliationWarnings(event: ReconciliationWarningsEvent): void {
@@ -328,8 +262,10 @@ export class VerboseEventHandler implements ExecutionEventListener {
   }
 
   public setModuleId(event: SetModuleIdEvent): void {
-    console.log(
-      chalk.yellowBright(`Starting validation for module: ${event.moduleName}`)
-    );
+    console.log(`Starting validation for module: ${event.moduleName}`);
+  }
+
+  public runStart(_event: RunStartEvent): void {
+    console.log("Execution run starting");
   }
 }


Test patch:
diff --git a/packages/core/test-integrations/fixture-projects/default-with-new-chain-id/ignition/deployments/chain-31337/journal.jsonl b/packages/core/test-integrations/fixture-projects/default-with-new-chain-id/ignition/deployments/chain-31337/journal.jsonl
index 3904c196..2cfa12c5 100644
--- a/packages/core/test-integrations/fixture-projects/default-with-new-chain-id/ignition/deployments/chain-31337/journal.jsonl
+++ b/packages/core/test-integrations/fixture-projects/default-with-new-chain-id/ignition/deployments/chain-31337/journal.jsonl
@@ -1,7 +1,7 @@
 
-{"chainId":123,"type":"RUN_START"}
+{"chainId":123,"type":"DEPLOYMENT_INITIALIZE"}
 {"artifactId":"LockModule:Lock","constructorArgs":[1987909200],"contractName":"Lock","dependencies":[],"from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","futureId":"LockModule:Lock","futureType":"NAMED_CONTRACT_DEPLOYMENT","libraries":{},"strategy":"basic","type":"DEPLOYMENT_EXECUTION_STATE_INITIALIZE","value":{"_kind":"bigint","value":"1000000000"}}
 {"futureId":"LockModule:Lock","networkInteraction":{"data":"0x60806040526040516105a23803806105a2833981810160405281019061002591906100f0565b804210610067576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161005e906101a0565b60405180910390fd5b8060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101c0565b600080fd5b6000819050919050565b6100cd816100ba565b81146100d857600080fd5b50565b6000815190506100ea816100c4565b92915050565b600060208284031215610106576101056100b5565b5b6000610114848285016100db565b91505092915050565b600082825260208201905092915050565b7f556e6c6f636b2074696d652073686f756c6420626520696e207468652066757460008201527f7572650000000000000000000000000000000000000000000000000000000000602082015250565b600061018a60238361011d565b91506101958261012e565b604082019050919050565b600060208201905081810360008301526101b98161017d565b9050919050565b6103d3806101cf6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063251c1aa3146100465780633ccfd60b146100645780638da5cb5b1461006e575b600080fd5b61004e61008c565b60405161005b919061024a565b60405180910390f35b61006c610092565b005b61007661020b565b60405161008391906102a6565b60405180910390f35b60005481565b6000544210156100d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ce9061031e565b60405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610167576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161015e9061038a565b60405180910390fd5b7fbf2ed60bd5b5965d685680c01195c9514e4382e28e3a5a2d2d5244bf59411b9347426040516101989291906103aa565b60405180910390a1600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610208573d6000803e3d6000fd5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000819050919050565b61024481610231565b82525050565b600060208201905061025f600083018461023b565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061029082610265565b9050919050565b6102a081610285565b82525050565b60006020820190506102bb6000830184610297565b92915050565b600082825260208201905092915050565b7f596f752063616e27742077697468647261772079657400000000000000000000600082015250565b60006103086016836102c1565b9150610313826102d2565b602082019050919050565b60006020820190508181036000830152610337816102fb565b9050919050565b7f596f75206172656e277420746865206f776e6572000000000000000000000000600082015250565b60006103746014836102c1565b915061037f8261033e565b602082019050919050565b600060208201905081810360008301526103a381610367565b9050919050565b60006040820190506103bf600083018561023b565b6103cc602083018461023b565b93925050505600000000000000000000000000000000000000000000000000000000767d1650","id":1,"type":"ONCHAIN_INTERACTION","value":{"_kind":"bigint","value":"1000000000"}},"type":"NETWORK_INTERACTION_REQUEST"}
 {"futureId":"LockModule:Lock","networkInteractionId":1,"nonce":0,"transaction":{"fees":{"maxFeePerGas":{"_kind":"bigint","value":"3000000000"},"maxPriorityFeePerGas":{"_kind":"bigint","value":"1000000000"}},"hash":"0x6b9830b7fe0d88787e8a757496c71ece7740ba1f10b4ff1be26ab8ec6d8ed61d"},"type":"TRANSACTION_SEND"}
 {"futureId":"LockModule:Lock","hash":"0x6b9830b7fe0d88787e8a757496c71ece7740ba1f10b4ff1be26ab8ec6d8ed61d","networkInteractionId":1,"receipt":{"blockHash":"0xf35aacce8d5fc6276fc544712013691b75fd980178c2a58e63bc37ee1cd76371","blockNumber":1,"contractAddress":"0x5fbdb2315678afecb367f032d93f642f64180aa3","logs":[],"status":"SUCCESS"},"type":"TRANSACTION_CONFIRM"}
-{"futureId":"LockModule:Lock","result":{"address":"0x5fbdb2315678afecb367f032d93f642f64180aa3","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"}
\ No newline at end of file
+{"futureId":"LockModule:Lock","result":{"address":"0x5fbdb2315678afecb367f032d93f642f64180aa3","type":"SUCCESS"},"type":"DEPLOYMENT_EXECUTION_STATE_COMPLETE"}
diff --git a/packages/core/test/execution/reducers/start-a-new-run.ts b/packages/core/test/execution/reducers/start-a-new-run.ts
index a1befb22..6b473aa4 100644
--- a/packages/core/test/execution/reducers/start-a-new-run.ts
+++ b/packages/core/test/execution/reducers/start-a-new-run.ts
@@ -13,7 +13,7 @@ describe("DeploymentStateReducer", () => {
       initialState = deploymentStateReducer(undefined);
 
       updatedState = deploymentStateReducer(initialState, {
-        type: JournalMessageType.RUN_START,
+        type: JournalMessageType.DEPLOYMENT_INITIALIZE,
         chainId: 31337,
       });
     });
diff --git a/packages/hardhat-plugin/test/execution/rerun-with-new-contract-deploy.ts b/packages/hardhat-plugin/test/execution/rerun-with-new-contract-deploy.ts
new file mode 100644
index 00000000..aa4f14ea
--- /dev/null
+++ b/packages/hardhat-plugin/test/execution/rerun-with-new-contract-deploy.ts
@@ -0,0 +1,74 @@
+/* eslint-disable import/no-unused-modules */
+import { buildModule } from "@nomicfoundation/ignition-core";
+import { assert } from "chai";
+
+import {
+  TestChainHelper,
+  useFileIgnitionProject,
+} from "../use-ignition-project";
+
+import { mineBlock } from "./helpers";
+
+/**
+ * Run an initial deploy, that deploys a contract. The module is modified
+ * to add an additional dependent contract. On the second run only one contract
+ * is deployed.
+ */
+describe("execution - rerun with new contract deploy", () => {
+  useFileIgnitionProject("minimal", "rerun-with-new-contract-deploy");
+
+  it("should deploy only one contract on second run", async function () {
+    const moduleDefinition = buildModule("BarModule", (m) => {
+      const bar = m.contract("Bar");
+
+      return {
+        bar,
+      };
+    });
+
+    // Start the deploy
+    const { bar: originalBar } = await this.runControlledDeploy(
+      moduleDefinition,
+      async (c: TestChainHelper) => {
+        // this block shound include deployment of foo1
+        await c.mineBlock(1);
+      }
+    );
+
+    const firstRunBarAddress = (await originalBar.getAddress()).toLowerCase();
+
+    // Further blocks with no pending transactions
+    await mineBlock(this.hre);
+    await mineBlock(this.hre);
+
+    const updatedModuleDefinition = buildModule("BarModule", (m) => {
+      const bar = m.contract("Bar");
+      const usesContract = m.contract("UsesContract", [bar]);
+
+      return {
+        bar,
+        usesContract,
+      };
+    });
+
+    // Rerun the deployment
+    const result = await this.runControlledDeploy(
+      updatedModuleDefinition,
+      async (c: TestChainHelper) => {
+        // this block shound include deployment of foo2
+        await c.mineBlock(1);
+      }
+    );
+
+    const usedAddress = (
+      await result.usesContract.contractAddress()
+    ).toLowerCase();
+
+    const secondRunBarAddress = (await result.bar.getAddress()).toLowerCase();
+
+    // The BarModule#Bar contract has not been redeployed if
+    // it shares the same address.
+    assert.equal(firstRunBarAddress, secondRunBarAddress);
+    assert.equal(usedAddress, secondRunBarAddress);
+  });
+});