Skip to content

Commit

Permalink
good first pass at setting up prod
Browse files Browse the repository at this point in the history
  • Loading branch information
dghelm committed Aug 24, 2024
1 parent ef99636 commit ff7ddf3
Show file tree
Hide file tree
Showing 15 changed files with 1,640 additions and 21 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@
},
"bugs": "https://github.com/scroll-tech/scroll-sdk-cli/issues",
"dependencies": {
"@iarna/toml": "^2.2.5",
"@inquirer/prompts": "^5.3.8",
"@kubernetes/client-node": "^0.21.0",
"@oclif/core": "^4",
"@oclif/plugin-help": "^6",
"@oclif/plugin-plugins": "^5",
"chalk": "^5.3.0",
"cli-progress": "^3.12.0",
"dockerode": "^4.0.2",
"ethers": "^6.13.2",
"js-yaml": "^4.1.0",
"ora": "^8.0.1",
"pg": "^8.12.0",
"qrcode": "^1.5.4",
"terminal-link": "^3.0.0",
"toml": "^3.0.0"
Expand All @@ -27,9 +30,11 @@
"@oclif/test": "^4",
"@types/chai": "^4",
"@types/cli-progress": "^3.11.6",
"@types/dockerode": "^3.3.31",
"@types/js-yaml": "^4.0.9",
"@types/mocha": "^10",
"@types/node": "^18",
"@types/pg": "^8.11.6",
"@types/qrcode": "^1.5.5",
"@types/sinon": "^17.0.3",
"chai": "^4",
Expand Down
49 changes: 34 additions & 15 deletions src/commands/helper/fund-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum Layer {
}

const FUNDING_AMOUNT = 0.004
const DEPLOYER_FUNDING_AMOUNT = 2

export default class HelperFundContracts extends Command {
static description = 'Fund L1 and L2 accounts for contracts'
Expand Down Expand Up @@ -54,6 +55,11 @@ export default class HelperFundContracts extends Command {
char: 'k',
description: 'Private key for funder wallet',
}),
'fund-deployer': Flags.boolean({
char: 'i',
description: 'Fund the deployer address only',
default: false,
}),
}

private l1Provider!: ethers.JsonRpcProvider
Expand Down Expand Up @@ -106,27 +112,40 @@ export default class HelperFundContracts extends Command {
this.fundingWallet = new ethers.Wallet(config.accounts.DEPLOYER_PRIVATE_KEY, this.l1Provider)
}

const l1Addresses = [
config.accounts.L1_COMMIT_SENDER_ADDR,
config.accounts.L1_FINALIZE_SENDER_ADDR,
config.accounts.L1_GAS_ORACLE_SENDER_ADDR,
]

const l2Addresses = [
config.accounts.L2_GAS_ORACLE_SENDER_ADDR,
]
if (flags['fund-deployer']) {
await this.fundDeployer(config.accounts.DEPLOYER_ADDR, flags)
} else {
const l1Addresses = [
config.accounts.L1_COMMIT_SENDER_ADDR,
config.accounts.L1_FINALIZE_SENDER_ADDR,
config.accounts.L1_GAS_ORACLE_SENDER_ADDR,
]

const l2Addresses = [
config.accounts.L2_GAS_ORACLE_SENDER_ADDR,
]

if (flags.account) {
l1Addresses.push(flags.account)
l2Addresses.push(flags.account)
}

if (flags.account) {
l1Addresses.push(flags.account)
l2Addresses.push(flags.account)
await this.fundL1Addresses(l1Addresses, flags)
await this.fundL2Addresses(l2Addresses, flags)
}

await this.fundL1Addresses(l1Addresses, flags)
await this.fundL2Addresses(l2Addresses, flags)

this.log(chalk.green('Funding complete'))
}

private async fundDeployer(deployerAddress: string, flags: any): Promise<void> {
this.log(chalk.cyan('\nFunding Deployer Address:'))
if (flags.dev) {
await this.fundAddressAnvil(this.l1Provider, deployerAddress, 100, Layer.L1)
} else {
await this.promptManualFunding(deployerAddress, DEPLOYER_FUNDING_AMOUNT, Layer.L1)
}
}

private async fundL1Addresses(addresses: string[], flags: any): Promise<void> {
this.log(chalk.cyan('\nFunding L1 Addresses:'))
for (const address of addresses) {
Expand Down
154 changes: 154 additions & 0 deletions src/commands/setup/configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { Command } from '@oclif/core'
import Docker from 'dockerode';
import * as fs from 'fs'
import * as path from 'path'
import * as toml from '@iarna/toml'

export default class SetupConfigs extends Command {
static override description = 'Generate configuration files and create environment files for services'

static override examples = [
'<%= config.bin %> <%= command.id %>',
]

private async runDockerCommand(): Promise<void> {
const docker = new Docker();
const image = 'scrolltech/scroll-stack-contracts:gen-configs-v0.0.16';

try {
// Pull the image if it doesn't exist locally
await docker.pull(image);

// Create and run the container
const container = await docker.createContainer({
Image: image,
Cmd: [], // Add any command if needed
HostConfig: {
Binds: [`${process.cwd()}:/contracts/volume`],
},
});

await container.start();

// Wait for the container to finish and get the logs
const stream = await container.logs({
follow: true,
stdout: true,
stderr: true,
});

// Print the logs
stream.pipe(process.stdout);

// Wait for the container to finish
await new Promise((resolve) => {
container.wait((err, data) => {
if (err) {
this.error(`Container exited with error: ${err}`);
} else if (data.StatusCode !== 0) {
this.error(`Container exited with status code: ${data.StatusCode}`);
}
resolve(null);
});
});

// Remove the container
await container.remove();

} catch (error) {
this.error(`Failed to run Docker command: ${error}`);
}
}

private createSecretsFolder(): void {
const secretsPath = path.join(process.cwd(), 'secrets')
if (!fs.existsSync(secretsPath)) {
fs.mkdirSync(secretsPath)
this.log('Created secrets folder')
} else {
this.log('Secrets folder already exists')
}
}

private async createEnvFiles(): Promise<void> {
const configPath = path.join(process.cwd(), 'config.toml')
if (!fs.existsSync(configPath)) {
this.error('config.toml not found in the current directory.')
return
}

const configContent = fs.readFileSync(configPath, 'utf-8')
const config = toml.parse(configContent)

const services = [
'bridge-history-fetcher', 'blockscout', 'chain-monitor', 'coordinator',
'event-watcher', 'gas-oracle', 'l1-explorer', 'l2-sequencer', 'rollup-node'
]

for (const service of services) {
const envFile = path.join(process.cwd(), 'secrets', `${service}-secret.env`)
const envContent = this.generateEnvContent(service, config)
fs.writeFileSync(envFile, envContent)
this.log(`Created ${service}-secret.env`)
}

// Create additional files
this.createMigrateDbFiles(config)
}

private generateEnvContent(service: string, config: any): string {
const mapping: Record<string, string[]> = {
'blockscout': ['BLOCKSCOUT_DB_CONNECTION_STRING:DATABASE_URL'],
'bridge-history-fetcher': ['BRIDGE_HISTORY_DB_CONNECTION_STRING:DATABASE_URL'],
'chain-monitor': ['CHAIN_MONITOR_DB_CONNECTION_STRING:DATABASE_URL'],
'coordinator': ['COORDINATOR_DB_CONNECTION_STRING:DATABASE_URL'],
'event-watcher': ['EVENT_WATCHER_DB_CONNECTION_STRING:DATABASE_URL'],
'gas-oracle': ['GAS_ORACLE_DB_CONNECTION_STRING:DATABASE_URL', 'L1_GAS_ORACLE_SENDER_PRIVATE_KEY:L1_GAS_ORACLE_SENDER_PRIVATE_KEY', 'L2_GAS_ORACLE_SENDER_PRIVATE_KEY:L2_GAS_ORACLE_SENDER_PRIVATE_KEY'],
'l1-explorer': ['L1_EXPLORER_DB_CONNECTION_STRING:DATABASE_URL'],
'l2-sequencer': ['L2GETH_KEYSTORE:L2GETH_KEYSTORE', 'L2GETH_PASSWORD:L2GETH_PASSWORD', 'L2GETH_NODEKEY:L2GETH_NODEKEY'],
'rollup-node': ['ROLLUP_NODE_DB_CONNECTION_STRING:DATABASE_URL', 'L1_COMMIT_SENDER_ADDR:L1_COMMIT_SENDER_ADDR', 'L1_FINALIZE_SENDER_ADDR:L1_FINALIZE_SENDER_ADDR'],
}

let content = ''
for (const pair of mapping[service] || []) {
const [configKey, envKey] = pair.split(':')
if (config.db && config.db[configKey]) {
content += `${envKey}="${config.db[configKey]}"\n`
} else if (config.accounts && config.accounts[configKey]) {
content += `${envKey}="${config.accounts[configKey]}"\n`
}
}
return content
}

private createMigrateDbFiles(config: any): void {
const migrateDbFiles = [
{ service: 'bridge-history-fetcher', key: 'BRIDGE_HISTORY_DB_CONNECTION_STRING' },
{ service: 'gas-oracle', key: 'GAS_ORACLE_DB_CONNECTION_STRING' },
{ service: 'rollup-node', key: 'ROLLUP_NODE_DB_CONNECTION_STRING' },
]

for (const file of migrateDbFiles) {
const filePath = path.join(process.cwd(), 'secrets', `${file.service}-migrate-db.json`)
const content = JSON.stringify({
driver_name: 'postgres',
dsn: config.db[file.key],
}, null, 2)
fs.writeFileSync(filePath, content)
this.log(`Created ${file.service}-migrate-db.json`)
}
}

public async run(): Promise<void> {
this.log('Running docker command to generate configs...')
await this.runDockerCommand()

this.log('Creating secrets folder...')
this.createSecretsFolder()

this.log('Creating environment files...')
await this.createEnvFiles()

this.log('Configuration setup completed.')
}
}
Loading

0 comments on commit ff7ddf3

Please sign in to comment.