Skip to content
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

New deployment result types #423

Merged
merged 12 commits into from
Aug 29, 2023
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
Loading