Skip to content

Commit

Permalink
fix(core): cancel existing deployments via proposals (sphinx-labs#1040)
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-goldman authored Sep 13, 2023
1 parent 21e3d7e commit 767b7c0
Show file tree
Hide file tree
Showing 16 changed files with 395 additions and 129 deletions.
6 changes: 6 additions & 0 deletions .changeset/curvy-bulldogs-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sphinx-labs/plugins': patch
'@sphinx-labs/core': patch
---

Cancel active deployments via proposals
45 changes: 21 additions & 24 deletions packages/core/src/actions/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ import {
CallAction,
HumanReadableActions,
AuthLeafFunctions,
UpgradeAuthAndManagerImpl,
CancelActiveDeployment,
} from './types'
import { getStorageLayout } from './artifacts'
import { getProjectBundleInfo } from '../tasks'
Expand Down Expand Up @@ -329,7 +331,8 @@ export const getEncodedAuthLeafData = (leaf: AuthLeaf): string => {
)

case AuthLeafFunctions.CANCEL_ACTIVE_DEPLOYMENT:
return coder.encode(['string'], [leaf.projectName])
// There isn't any data for this leaf type, so we don't encode anything.
return coder.encode([], [])

/****************************** PROPOSER ACTIONS ******************************/

Expand Down Expand Up @@ -820,13 +823,26 @@ export const getAuthLeafsForChain = async (
// because the first two indexes are reserved for the setup and proposal leafs.
let index = firstProposalOccurred ? 1 : 2

// If a previous deployment is currently executing, we cancel it. The user may need to cancel the
// previous deployment if one of their actions reverted during the execution process.
if (configCache.isExecuting) {
const cancelDeploymentLeaf: CancelActiveDeployment = {
chainId,
to: manager,
index,
leafType: AuthLeafFunctions.CANCEL_ACTIVE_DEPLOYMENT,
}
index += 1
leafs.push(cancelDeploymentLeaf)
}

const managerVersionString = `v${configCache.managerVersion.major}.${configCache.managerVersion.minor}.${configCache.managerVersion.patch}`
if (
managerVersionString !== parsedConfig.options.managerVersion &&
!configCache.isManagerDeployed
) {
const version = parseSemverVersion(parsedConfig.options.managerVersion)
const upgradeLeaf: AuthLeaf = {
const upgradeLeaf: UpgradeAuthAndManagerImpl = {
chainId,
to: manager,
index,
Expand Down Expand Up @@ -937,33 +953,13 @@ export const findBundledLeaf = (
return leaf
}

/**
* @notice Gets the proposal request leaf for a given chain-specific index and chain ID.
*
* @param proposalRequestLeafs List of ProposalRequest leafs.
* @param index Index of the leaf on the specified chain.
* @param chainId Chain ID of the leaf.
*/
export const findProposalRequestLeaf = (
proposalRequestLeafs: Array<ProposalRequestLeaf>,
index: number,
chainId: number
): ProposalRequestLeaf => {
const leaf = proposalRequestLeafs.find(
(l) => l.index === index && l.chainId === chainId
)
if (!leaf) {
throw new Error(`Leaf not found for index ${index} and chainId ${chainId}`)
}
return leaf
}

export const getProjectDeploymentForChain = async (
leafs: Array<AuthLeaf>,
chainId: number,
projectName: string,
configUri: string,
bundles: SphinxBundles
bundles: SphinxBundles,
isExecuting: boolean
): Promise<ProjectDeployment | undefined> => {
const approvalLeafs = leafs
.filter(isApproveDeploymentAuthLeaf)
Expand All @@ -983,6 +979,7 @@ export const getProjectDeploymentForChain = async (
chainId,
deploymentId,
name: projectName,
isExecuting,
}
}

Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ interface UpgradeAuthImplementation extends BaseAuthLeaf {
data: string
}

interface UpgradeAuthAndManagerImpl extends BaseAuthLeaf {
export interface UpgradeAuthAndManagerImpl extends BaseAuthLeaf {
leafType: AuthLeafFunctions.UPGRADE_MANAGER_AND_AUTH_IMPL
managerImpl: string
managerInitCallData: string
Expand All @@ -298,9 +298,8 @@ export interface ApproveDeployment extends BaseAuthLeaf {
approval: DeploymentApproval
}

interface CancelActiveDeployment extends BaseAuthLeaf {
export interface CancelActiveDeployment extends BaseAuthLeaf {
leafType: AuthLeafFunctions.CANCEL_ACTIVE_DEPLOYMENT
projectName: string
}

interface Propose extends BaseAuthLeaf {
Expand Down Expand Up @@ -361,10 +360,16 @@ export type ProposalRequest = {
}
}

/**
* @param name The name of the project.
* @param isExecuting Whether there's currently an active deployment in the SphinxManager on this
* chain.
*/
export type ProjectDeployment = {
chainId: number
deploymentId: string
name: string // project name
name: string
isExecuting: boolean
}

export type ProposalRequestLeaf = {
Expand Down
20 changes: 13 additions & 7 deletions packages/core/src/config/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2941,7 +2941,18 @@ export const getConfigCache = async (
await provider.getNetwork(),
networkType
)
const isManagerDeployed_ = await registry.isManagerDeployed(managerAddress)
const isManagerDeployed_: boolean = await registry.isManagerDeployed(
managerAddress
)

const SphinxManager = new ethers.Contract(
managerAddress,
SphinxManagerABI,
provider
)

const isExecuting =
isManagerDeployed_ && (await SphinxManager.isExecuting()) === true

const contractConfigCache: ContractConfigCache = {}
for (const [referenceName, parsedContractConfig] of Object.entries(
Expand Down Expand Up @@ -3072,12 +3083,6 @@ export const getConfigCache = async (
}
}

const SphinxManager = new ethers.Contract(
managerAddress,
SphinxManagerABI,
provider
)

const managerVersion: SemverVersion = isManagerDeployed_
? await SphinxManager.version()
: CURRENT_SPHINX_MANAGER_VERSION
Expand All @@ -3098,6 +3103,7 @@ export const getConfigCache = async (

return {
isManagerDeployed: isManagerDeployed_,
isExecuting,
managerVersion,
chainId,
networkType,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ export type ConfigArtifacts = {
*/
export interface MinimalConfigCache {
isManagerDeployed: boolean
isExecuting: boolean
managerVersion: SemverVersion
blockGasLimit: bigint
chainId: number
Expand Down Expand Up @@ -369,7 +370,6 @@ export interface CanonicalConfig {
manager: string
projectName: string
options: ConfigOptions
contracts: ParsedContractConfigs
chainStates: {
[chainId: number]: {
firstProposalOccurred: boolean
Expand Down
7 changes: 2 additions & 5 deletions packages/core/src/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ export const proposeAbstractTask = async (
chainId,
projectName,
configUri,
bundles
bundles,
configCache.isExecuting
)
if (projectDeployment) {
projectDeployments.push(projectDeployment)
Expand Down Expand Up @@ -361,10 +362,6 @@ export const proposeAbstractTask = async (
const newCanonicalConfig: CanonicalConfig = {
manager: prevConfig.manager,
options: parsedConfig.options,
contracts: {
...prevConfig.contracts,
...parsedConfig.contracts,
},
projectName: parsedConfig.projectName,
chainStates: {
...prevConfig.chainStates,
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,6 @@ export const getEmptyCanonicalConfig = (
proposers: [],
managerVersion: 'v0.2.4',
},
contracts: {},
chainStates,
}
}
Expand Down Expand Up @@ -1391,7 +1390,6 @@ export const toCanonicalConfig = async (
projectName,
manager: managerAddress,
options: parsedConfig.options,
contracts: parsedConfig.contracts,
chainStates,
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/test/diff.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const originalParsedConfig: ParsedConfig = {
const callHash = getCallHash(callAction.to, callAction.data)
const originalConfigCache: ConfigCache = {
isManagerDeployed: false,
isExecuting: false,
chainId: 10,
networkName: 'optimism',
contractConfigCache: {
Expand Down
12 changes: 10 additions & 2 deletions packages/plugins/contracts/foundry/Sphinx.sol
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,19 @@ abstract contract Sphinx {
} else {
vm.recordLogs();
// manager.executeInitialActions{ gas: bufferedGasLimit }(rawActions, _proofs);
(bool success, bytes memory result) = address(manager).call{ gas: bufferedGasLimit }(abi.encodeWithSignature("executeInitialActions((uint8,uint256,bytes)[],bytes32[][])", rawActions, _proofs));
(bool success, bytes memory result) = address(manager).call{
gas: bufferedGasLimit
}(
abi.encodeWithSignature(
"executeInitialActions((uint8,uint256,bytes)[],bytes32[][])",
rawActions,
_proofs
)
);
if (!success) {
uint256 failureIndex;
assembly {
failureIndex := mload(add(result,0x24))
failureIndex := mload(add(result, 0x24))
}

return (DeploymentStatus.FAILED, failureIndex);
Expand Down
131 changes: 92 additions & 39 deletions packages/plugins/contracts/foundry/SphinxConstants.sol

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/plugins/contracts/foundry/SphinxPluginTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct FoundryContractConfig {

struct ConfigCache {
bool isManagerDeployed;
bool isExecuting;
Version managerVersion;
uint256 blockGasLimit;
uint256 chainId;
Expand Down
2 changes: 2 additions & 0 deletions packages/plugins/contracts/foundry/SphinxUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ contract SphinxUtils is
string memory _mainFfiScriptPath
) external returns (ConfigCache memory) {
bool isManagerDeployed_ = _registry.isManagerDeployed(address(_manager));
bool isExecuting = isManagerDeployed_ && _manager.isExecuting();

ContractConfigCache[] memory contractConfigCache = new ContractConfigCache[](
_minimalConfig.contracts.length
Expand Down Expand Up @@ -543,6 +544,7 @@ contract SphinxUtils is
return
ConfigCache({
isManagerDeployed: isManagerDeployed_,
isExecuting: isExecuting,
managerVersion: managerVersion,
blockGasLimit: block.gaslimit,
chainId: block.chainid,
Expand Down
1 change: 1 addition & 0 deletions packages/plugins/src/foundry/structs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const decodeCachedConfig = (
blockGasLimit: configCache.blockGasLimit,
chainId: parseInt(configCache.chainId, 10),
isManagerDeployed: configCache.isManagerDeployed,
isExecuting: configCache.isExecuting,
managerVersion: configCache.managerVersion,
contractConfigCache,
callNonces,
Expand Down
Loading

0 comments on commit 767b7c0

Please sign in to comment.