Skip to content

Commit

Permalink
add code ID to both UI JSON config and indexer deployment config
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Nov 8, 2024
1 parent f1c92cf commit acb2873
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 40 deletions.
3 changes: 3 additions & 0 deletions packages/dispatch/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ contract_dirs = [
"/Users/user/Developer/dao-contracts/artifacts",
"/Users/user/Developer/polytone/artifacts",
]

### The path to the ansible indexer group_vars folder in the ops repo.
indexer_ansible_group_vars_path = "/Users/user/Developer/ops/ansible/group_vars"
164 changes: 153 additions & 11 deletions packages/dispatch/scripts/deploy/CodeIdConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import chalk from 'chalk'
import lockfile from 'proper-lockfile'
import semverCompare from 'semver/functions/compare'

import { chainIdToIndexerGroupVarsName } from './config'

/**
* Path to all uploaded code IDs.
*/
Expand All @@ -21,7 +23,7 @@ type CodeIds = Record<string, Record<string, Record<string, number>>>
export class CodeIdConfig {
private _codeIds: CodeIds = {}

constructor() {
constructor(private indexerAnsibleGroupVarsPath: string) {
if (!fs.existsSync(codeIdsPath)) {
console.log(chalk.red(`Code IDs file not found at ${codeIdsPath}`))
process.exit(1)
Expand All @@ -40,10 +42,40 @@ export class CodeIdConfig {
fs.writeFileSync(codeIdsPath, JSON.stringify(this._codeIds, null, 2))
}

async setCodeId({
/**
* Set code ID in the frontend config and the indexer config.
*/
async setCodeId(options: {
/**
* The chain ID.
*/
chainId: string
/**
* The contract version being deployed.
*/
version: string
/**
* The contract name being deployed.
*/
name: string
/**
* The code ID being set.
*/
codeId: number
}) {
await Promise.all([
this.setCodeIdUiConfig(options),
this.setCodeIdIndexerConfig(options),
])
}

/**
* Set code ID in the frontend config.
*/
private async setCodeIdUiConfig({
chainId,
version,
name: _name,
name,
codeId,
}: {
/**
Expand Down Expand Up @@ -74,8 +106,6 @@ export class CodeIdConfig {
})

try {
const name = contractNameToCodeIdName(_name)

this.load()

if (!this._codeIds[chainId]) {
Expand All @@ -85,7 +115,8 @@ export class CodeIdConfig {
this._codeIds[chainId][version] = {}
}

this._codeIds[chainId][version][name] = codeId
const configName = contractNameToJsonConfigName(name)
this._codeIds[chainId][version][configName] = codeId

this.save()
} finally {
Expand All @@ -94,6 +125,110 @@ export class CodeIdConfig {
}
}

/**
* Set code ID in the indexer config.
*/
private async setCodeIdIndexerConfig({
chainId,
name,
codeId,
}: {
/**
* The chain ID.
*/
chainId: string
/**
* The contract name being deployed.
*/
name: string
/**
* The code ID being set.
*/
codeId: number
}) {
const indexerGroupVarsName = chainIdToIndexerGroupVarsName[chainId]
if (!indexerGroupVarsName) {
throw new Error(
`No indexer group vars name found for chain ID ${chainId}`
)
}

const indexerGroupVarsPath = path.join(
this.indexerAnsibleGroupVarsPath,
indexerGroupVarsName + '.yml'
)

// Establish lock.
const releaseLock = await lockfile.lock(indexerGroupVarsPath, {
retries: {
forever: true,
minTimeout: 100,
factor: 1.1,
randomize: true,
},
})

try {
const configName = contractNameToIndexerGroupVarsName(name)

const fileContents = fs
.readFileSync(indexerGroupVarsPath, 'utf8')
.trimEnd()
const lines = fileContents.split('\n')

// Get line index of the start of the `indexer_code_ids:` map.
const indexerCodeIdsMapKeyLineIndex = lines.findIndex(
(line) => line === 'indexer_code_ids:'
)
if (indexerCodeIdsMapKeyLineIndex === -1) {
throw new Error('indexer_code_ids map not found in indexer group vars')
}

const codeIdMapStartIndex = indexerCodeIdsMapKeyLineIndex + 1
// Get last line of the `indexer_code_ids:` map by finding the first
// non-indented line.
let codeIdMapEndIndex = lines.findIndex(
(line, index) => index >= codeIdMapStartIndex && !line.startsWith(' ')
)
// If none found, all lines are indented and we're at the end.
if (codeIdMapEndIndex === -1) {
codeIdMapEndIndex = lines.length
}

const entries = lines.slice(codeIdMapStartIndex, codeIdMapEndIndex)

// Find the line with this contract name.
const contractIndex = entries.findIndex((line) =>
line.startsWith(` ${configName}:`)
)

// If not found, add it to the end.
if (contractIndex === -1) {
entries.push(` ${configName}: [${codeId}]`)
} else {
// If found, add code ID to the end, unless it already exists.
const entry = entries[contractIndex]
if (!new RegExp(`\\b${codeId}\\b`).test(entry)) {
entries[contractIndex] = entry.endsWith('[]')
? entry.replace(/\[\]$/, `[${codeId}]`)
: entry.replace(/\]$/, `, ${codeId}]`)
}
}

// Sort entries.
entries.sort()

// Replace old entries with new set.
lines.splice(codeIdMapStartIndex, entries.length, ...entries)

// Write changes to file.
fs.writeFileSync(indexerGroupVarsPath, lines.join('\n') + '\n')
} finally {
// Release lock.
await releaseLock()
}
}

/**
* Get the most recent code ID and version for this chain, or null if code ID
* has not been set for this chain.
Expand Down Expand Up @@ -131,14 +266,13 @@ export class CodeIdConfig {
})

try {
const name = contractNameToCodeIdName(_name)

this.load()

const versionsDescending = Object.keys(this._codeIds[chainId])
.sort(semverCompare)
.reverse()

const name = contractNameToJsonConfigName(_name)
for (const version of versionsDescending) {
if (typeof this._codeIds[chainId]?.[version]?.[name] === 'number') {
return {
Expand Down Expand Up @@ -187,7 +321,7 @@ export class CodeIdConfig {
})

try {
const name = contractNameToCodeIdName(_name)
const name = contractNameToJsonConfigName(_name)

this.load()

Expand All @@ -204,10 +338,18 @@ export class CodeIdConfig {
}

/**
* Convert snake case contract name to title case code ID name.
* Convert snake case contract name to title case codeIds.json config name.
*/
export const contractNameToCodeIdName = (name: string) =>
export const contractNameToJsonConfigName = (name: string) =>
name
.split(/[_\-]/g)
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join('')

/**
* Convert snake case contract name to escaped indexer group vars name.
*
* Replace underscore with double underscore.
*/
export const contractNameToIndexerGroupVarsName = (name: string) =>
name.replace(/_/g, '__')
66 changes: 61 additions & 5 deletions packages/dispatch/scripts/deploy/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { ChainId } from '@dao-dao/types'

type DeploySet = {
export type DeploySetContract =
| string
| {
/**
* File name of the contract to deploy.
*/
file: string
/**
* Actual alias to use as the name for the contract.
*/
alias: string
}

export type DeploySet = {
name: string
/**
* The type of set to deploy.
Expand All @@ -14,7 +27,7 @@ type DeploySet = {
/**
* Contracts to deploy.
*/
contracts: string[]
contracts: DeploySetContract[]
/**
* If defined, only deploy the set for the given chain IDs.
*/
Expand Down Expand Up @@ -81,15 +94,25 @@ export const deploySets: DeploySet[] = [
{
name: 'cw-vesting with staking',
type: 'always',
contracts: ['cw_vesting-staking'],
contracts: [
{
file: 'cw_vesting-staking',
alias: 'cw_vesting',
},
],
skipChainIds: [ChainId.NeutronMainnet, ChainId.NeutronTestnet],
},

// cw-vesting without staking
{
name: 'cw-vesting without staking',
type: 'always',
contracts: ['cw_vesting-no_staking'],
contracts: [
{
file: 'cw_vesting-no_staking',
alias: 'cw_vesting',
},
],
chainIds: [ChainId.NeutronMainnet, ChainId.NeutronTestnet],
},

Expand Down Expand Up @@ -231,7 +254,12 @@ export const deploySets: DeploySet[] = [
{
name: 'token factory kujira',
type: 'always',
contracts: ['cw_tokenfactory_issuer-kujira'],
contracts: [
{
file: 'cw_tokenfactory_issuer-kujira',
alias: 'cw_tokenfactory_issuer',
},
],
chainIds: [ChainId.KujiraMainnet, ChainId.KujiraTestnet],
},

Expand Down Expand Up @@ -293,3 +321,31 @@ export const deploySets: DeploySet[] = [
chainIds: [ChainId.OmniflixHubMainnet, ChainId.OmniflixHubTestnet],
},
]

/**
* Map chain ID to indexer ansible group_vars name.
*/
export const chainIdToIndexerGroupVarsName: Record<string, string> = {
[ChainId.BitsongMainnet]: 'bitsong_mainnet',
[ChainId.BitsongTestnet]: 'bitsong_testnet',
[ChainId.CosmosHubMainnet]: 'cosmosHub_mainnet',
[ChainId.CosmosHubProviderTestnet]: 'cosmosHubProvider_testnet',
[ChainId.CosmosHubThetaTestnet]: 'cosmosHubTheta_testnet',
[ChainId.JunoMainnet]: 'juno_mainnet',
[ChainId.JunoTestnet]: 'juno_testnet',
[ChainId.KujiraMainnet]: 'kujira_mainnet',
[ChainId.KujiraTestnet]: 'kujira_testnet',
[ChainId.MigalooMainnet]: 'migaloo_mainnet',
[ChainId.MigalooTestnet]: 'migaloo_testnet',
[ChainId.NeutronMainnet]: 'neutron_mainnet',
[ChainId.NeutronTestnet]: 'neutron_testnet',
[ChainId.OmniflixHubMainnet]: 'omniflix_mainnet',
[ChainId.OmniflixHubTestnet]: 'omniflix_testnet',
[ChainId.OraichainMainnet]: 'oraichain_mainnet',
[ChainId.OsmosisMainnet]: 'osmosis_mainnet',
[ChainId.OsmosisTestnet]: 'osmosis_testnet',
[ChainId.StargazeMainnet]: 'stargaze_mainnet',
[ChainId.StargazeTestnet]: 'stargaze_testnet',
[ChainId.TerraMainnet]: 'terra_mainnet',
[ChainId.TerraClassicMainnet]: 'terraClassic_mainnet',
}
Loading

0 comments on commit acb2873

Please sign in to comment.