Skip to content

Commit

Permalink
Merge pull request #423 from NomicFoundation/return-types
Browse files Browse the repository at this point in the history
New deployment result types
  • Loading branch information
alcuadrado authored Aug 29, 2023
2 parents b4de520 + 5052cac commit 08a20ff
Show file tree
Hide file tree
Showing 49 changed files with 1,058 additions and 512 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { wipe } from "./new-api/wipe";
export { StoredDeploymentSerializer } from "./new-api/stored-deployment-serializer";
export * from "./new-api/type-guards";
export * from "./new-api/types/artifact";
export * from "./new-api/types/deployer";
export * from "./new-api/types/deploy";
export * from "./new-api/types/module";
export * from "./new-api/types/module-builder";
export * from "./new-api/types/provider";
Expand Down
18 changes: 13 additions & 5 deletions packages/core/src/new-api/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ import {
DeployConfig,
DeploymentParameters,
DeploymentResult,
} from "./types/deployer";
import { IgnitionModule } from "./types/module";
} from "./types/deploy";
import { IgnitionModule, IgnitionModuleResult } from "./types/module";
import { EIP1193Provider } from "./types/provider";

/**
* Deploy an IgnitionModule to the chain
*
* @beta
*/
export async function deploy({
export async function deploy<
ModuleIdT extends string,
ContractNameT extends string,
IgnitionModuleResultsT extends IgnitionModuleResult<ContractNameT>
>({
config = {},
artifactResolver,
provider,
Expand All @@ -41,12 +45,16 @@ export async function deploy({
artifactResolver: ArtifactResolver;
provider: EIP1193Provider;
deploymentDir?: string;
ignitionModule: IgnitionModule;
ignitionModule: IgnitionModule<
ModuleIdT,
ContractNameT,
IgnitionModuleResultsT
>;
deploymentParameters: DeploymentParameters;
accounts: string[];
verbose: boolean;
defaultSender?: string;
}): Promise<DeploymentResult> {
}): Promise<DeploymentResult<ContractNameT, IgnitionModuleResultsT>> {
await validateStageOne(ignitionModule, artifactResolver);

if (defaultSender !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/new-api/internal/defaultConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeployConfig } from "../types/deployer";
import { DeployConfig } from "../types/deploy";

/**
* Ignitions default deployment configuration values.
Expand Down
206 changes: 158 additions & 48 deletions packages/core/src/new-api/internal/deployer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import type { IgnitionModule } from "../types/module";
import type { IgnitionModule, IgnitionModuleResult } from "../types/module";

import { IgnitionError } from "../../errors";
import { isContractFuture } from "../type-guards";
import { ArtifactResolver } from "../types/artifact";
import {
DeployConfig,
DeploymentParameters,
DeploymentResult,
DeploymentResultContracts,
} from "../types/deployer";
DeploymentResultType,
ExecutionErrorDeploymentResult,
ReconciliationErrorDeploymentResult,
SuccessfulDeploymentResult,
} from "../types/deploy";

import { Batcher } from "./batcher";
import { DeploymentLoader } from "./deployment-loader/types";
Expand All @@ -19,15 +21,18 @@ import {
import { ExecutionEngine } from "./new-execution/execution-engine";
import { JsonRpcClient } from "./new-execution/jsonrpc-client";
import { DeploymentState } from "./new-execution/types/deployment-state";
import { ExecutionResultType } from "./new-execution/types/execution-result";
import {
CallExecutionState,
ContractAtExecutionState,
DeploymentExecutionState,
ExecutionSateType,
ExecutionState,
ExecutionStatus,
SendDataExecutionState,
StaticCallExecutionState,
} from "./new-execution/types/execution-state";
import { ExecutionStrategy } from "./new-execution/types/execution-strategy";
import { findDeployedContracts } from "./new-execution/views/find-deployed-contracts";
import { Reconciler } from "./reconciliation/reconciler";
import { assertIgnitionInvariant } from "./utils/assertions";
import { getFuturesFromModule } from "./utils/get-futures-from-module";
Expand All @@ -52,19 +57,31 @@ export class Deployer {
);
}

public async deploy(
ignitionModule: IgnitionModule,
public async deploy<
ModuleIdT extends string,
ContractNameT extends string,
IgnitionModuleResultsT extends IgnitionModuleResult<ContractNameT>
>(
ignitionModule: IgnitionModule<
ModuleIdT,
ContractNameT,
IgnitionModuleResultsT
>,
deploymentParameters: DeploymentParameters,
accounts: string[],
defaultSender: string
): Promise<DeploymentResult> {
await validateStageTwo(
): Promise<DeploymentResult<ContractNameT, IgnitionModuleResultsT>> {
const validationResult = await validateStageTwo(
ignitionModule,
this._artifactResolver,
deploymentParameters,
accounts
);

if (validationResult !== null) {
return validationResult;
}

let deploymentState = await this._getOrInitializeDeploymentState();

const contracts =
Expand Down Expand Up @@ -98,11 +115,23 @@ export class Deployer {
);

if (reconciliationResult.reconciliationFailures.length > 0) {
const failures = reconciliationResult.reconciliationFailures
.map((rf) => ` ${rf.futureId} - ${rf.failure}`)
.join("\n");
const errors: ReconciliationErrorDeploymentResult["errors"] = {};

for (const {
futureId,
failure,
} of reconciliationResult.reconciliationFailures) {
if (errors[futureId] === undefined) {
errors[futureId] = [];
}

errors[futureId].push(failure);
}

throw new IgnitionError(`Reconciliation failed\n\n${failures}`);
return {
type: DeploymentResultType.RECONCILIATION_ERROR,
errors,
};
}

if (reconciliationResult.missingExecutedFutures.length > 0) {
Expand Down Expand Up @@ -131,47 +160,38 @@ export class Deployer {
defaultSender
);

return this._getDeploymentResult(
deploymentState,
this._deploymentLoader,
ignitionModule
);
return this._getDeploymentResult(deploymentState, ignitionModule);
}

private async _getDeploymentResult(
private async _getDeploymentResult<
ModuleIdT extends string,
ContractNameT extends string,
IgnitionModuleResultsT extends IgnitionModuleResult<ContractNameT>
>(
deploymentState: DeploymentState,
deploymentLoader: DeploymentLoader,
module: IgnitionModule
): Promise<DeploymentResult> {
if (
Object.values(deploymentState.executionStates).some(
(ex) => ex.status !== ExecutionStatus.SUCCESS
)
) {
// TODO: deal with failure cases and error cases
throw new Error("TBD: error result against future");
}

const deployedContracts: DeploymentResultContracts = {};

for (const {
futureId,
contractName,
contractAddress,
} of findDeployedContracts(deploymentState)) {
const artifact = await deploymentLoader.loadArtifact(futureId);

deployedContracts[futureId] = {
contractName,
contractAddress,
artifact,
};
module: IgnitionModule<ModuleIdT, ContractNameT, IgnitionModuleResultsT>
): Promise<DeploymentResult<ContractNameT, IgnitionModuleResultsT>> {
if (!this._isSuccessful(deploymentState)) {
return this._getExecutionErrorResult(deploymentState);
}

return {
status: "success",
contracts: deployedContracts,
module,
type: DeploymentResultType.SUCCESSFUL_DEPLOYMENT,
contracts: Object.fromEntries(
Object.entries(module.results).map(([name, contractFuture]) => [
name,
{
id: contractFuture.id,
contractName: contractFuture.contractName,
address: getContractAddress(
deploymentState.executionStates[contractFuture.id]
),
},
])
) as SuccessfulDeploymentResult<
ContractNameT,
IgnitionModuleResultsT
>["contracts"],
};
}

Expand All @@ -190,4 +210,94 @@ export class Deployer {

return deploymentState;
}

private _isSuccessful(deploymentState: DeploymentState): boolean {
return Object.values(deploymentState.executionStates).every(
(ex) => ex.status === ExecutionStatus.SUCCESS
);
}

private _getExecutionErrorResult(
deploymentState: DeploymentState
): ExecutionErrorDeploymentResult {
return {
type: DeploymentResultType.EXECUTION_ERROR,
started: Object.values(deploymentState.executionStates)
.filter((ex) => ex.status === ExecutionStatus.STARTED)
.map((ex) => ex.id),
successful: Object.values(deploymentState.executionStates)
.filter((ex) => ex.status === ExecutionStatus.SUCCESS)
.map((ex) => ex.id),
timedOut: Object.values(deploymentState.executionStates)
.filter(canTimeout)
.filter((ex) => ex.status === ExecutionStatus.TIMEOUT)
.map((ex) => ({
futureId: ex.id,
executionId: ex.networkInteractions.at(-1)!.id,
})),
failed: Object.values(deploymentState.executionStates)
.filter(canFail)
.filter((ex) => ex.status === ExecutionStatus.FAILED)
.map((ex) => ({
futureId: ex.id,
executionId: ex.networkInteractions.at(-1)!.id,
error: "TODO: format the execution result into a string",
})),
};
}
}

// TODO: Does this exist anywhere else? It's in fact just checking if it sends txs
function canTimeout(
exState: ExecutionState
): exState is
| DeploymentExecutionState
| CallExecutionState
| SendDataExecutionState {
return (
exState.type === ExecutionSateType.DEPLOYMENT_EXECUTION_STATE ||
exState.type === ExecutionSateType.CALL_EXECUTION_STATE ||
exState.type === ExecutionSateType.SEND_DATA_EXECUTION_STATE
);
}

// TODO: Does this exist anywhere else? It's in fact just checking if has network interactions
function canFail(
exState: ExecutionState
): exState is
| DeploymentExecutionState
| CallExecutionState
| SendDataExecutionState
| StaticCallExecutionState {
return (
exState.type === ExecutionSateType.DEPLOYMENT_EXECUTION_STATE ||
exState.type === ExecutionSateType.CALL_EXECUTION_STATE ||
exState.type === ExecutionSateType.SEND_DATA_EXECUTION_STATE ||
exState.type === ExecutionSateType.STATIC_CALL_EXECUTION_STATE
);
}

// TODO: Does this exist somewhere else?
function getContractAddress(exState: ExecutionState): string {
assertIgnitionInvariant(
exState.type === ExecutionSateType.DEPLOYMENT_EXECUTION_STATE ||
exState.type === ExecutionSateType.CONTRACT_AT_EXECUTION_STATE,
`Execution state ${exState.id} should be a deployment or contract at execution state`
);

assertIgnitionInvariant(
exState.status === ExecutionStatus.SUCCESS,
`Cannot get contract address from execution state ${exState.id} because it is not successful`
);

if (exState.type === ExecutionSateType.CONTRACT_AT_EXECUTION_STATE) {
return exState.contractAddress;
}

assertIgnitionInvariant(
exState.result?.type === ExecutionResultType.SUCCESS,
`Cannot get contract address from execution state ${exState.id} because it is not successful`
);

return exState.result.address;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IgnitionError } from "../../../errors";
import { ArtifactResolver } from "../../types/artifact";
import { DeploymentParameters } from "../../types/deployer";
import { DeploymentParameters } from "../../types/deploy";
import {
Future,
IgnitionModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ArtifactResolver } from "../../../types/artifact";
import { DeploymentParameters } from "../../../types/deployer";
import { DeploymentParameters } from "../../../types/deploy";
import { Future } from "../../../types/module";
import { DeploymentLoader } from "../../deployment-loader/types";
import { assertIgnitionInvariant } from "../../utils/assertions";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeploymentParameters } from "../../../../types/deployer";
import { DeploymentParameters } from "../../../../types/deploy";
import { Future, FutureType } from "../../../../types/module";
import { DeploymentLoader } from "../../../deployment-loader/types";
import { DeploymentState } from "../../types/deployment-state";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isAddress } from "ethers";

import { isModuleParameterRuntimeValue } from "../../../../type-guards";
import { DeploymentParameters } from "../../../../types/deployer";
import { DeploymentParameters } from "../../../../types/deploy";
import {
AccountRuntimeValue,
AddressResolvableFuture,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ArtifactResolver } from "../../types/artifact";
import { DeploymentParameters } from "../../types/deployer";
import { DeploymentParameters } from "../../types/deploy";
import { Future, IgnitionModule } from "../../types/module";
import { DeploymentLoader } from "../deployment-loader/types";
import { DeploymentState } from "../new-execution/types/deployment-state";
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/new-api/internal/reconciliation/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ArtifactResolver } from "../../types/artifact";
import { DeploymentParameters } from "../../types/deployer";
import { DeploymentParameters } from "../../types/deploy";
import { Future } from "../../types/module";
import { DeploymentLoader } from "../deployment-loader/types";
import { DeploymentState } from "../new-execution/types/deployment-state";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeploymentParameters } from "../../types/deployer";
import { DeploymentParameters } from "../../types/deploy";
import {
ModuleParameterRuntimeValue,
ModuleParameterType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IgnitionValidationError } from "../../../../errors";
import { isModuleParameterRuntimeValue } from "../../../type-guards";
import { ArtifactResolver } from "../../../types/artifact";
import { DeploymentParameters } from "../../../types/deployer";
import { DeploymentParameters } from "../../../types/deploy";
import { ArtifactContractAtFuture } from "../../../types/module";

export async function validateArtifactContractAt(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
isModuleParameterRuntimeValue,
} from "../../../type-guards";
import { ArtifactResolver } from "../../../types/artifact";
import { DeploymentParameters } from "../../../types/deployer";
import { DeploymentParameters } from "../../../types/deploy";
import { ArtifactContractDeploymentFuture } from "../../../types/module";
import {
retrieveNestedRuntimeValues,
Expand Down
Loading

0 comments on commit 08a20ff

Please sign in to comment.