diff --git a/packages/agoric-cli/lib/chain-config.js b/packages/agoric-cli/lib/chain-config.js index 02553a456a8..00c57b0ff8e 100644 --- a/packages/agoric-cli/lib/chain-config.js +++ b/packages/agoric-cli/lib/chain-config.js @@ -27,7 +27,7 @@ export function finishCosmosConfig({ // Update addresses in the config. config.p2p.laddr = `tcp://0.0.0.0:${rpcPort - 1}`; config.p2p.persistent_peers = persistentPeers; - config.rpc.laddr = `tcp://127.0.0.1:${rpcPort}`; + config.rpc.laddr = `tcp://0.0.0.0:${rpcPort}`; // Needed for IBC. config.tx_index.index_all_keys = true; diff --git a/packages/agoric-cli/lib/start.js b/packages/agoric-cli/lib/start.js index db934f49b6a..83141cc83e7 100644 --- a/packages/agoric-cli/lib/start.js +++ b/packages/agoric-cli/lib/start.js @@ -9,6 +9,9 @@ import { finishCosmosGenesis, } from './chain-config'; +const SDK_IMAGE = `agoric/agoric-sdk`; +const SOLO_IMAGE = `agoric/cosmic-swingset-solo`; + const PROVISION_COINS = `100000000${STAKING_DENOM},100000000${MINT_DENOM},100provisionpass,100sendpacketpass`; const DELEGATE0_COINS = `50000000${STAKING_DENOM}`; const CHAIN_ID = 'agoric'; @@ -109,17 +112,24 @@ export default async function startMain(progname, rawArgs, powers, opts) { }; let agSolo; - let agServer; if (opts.sdk) { agSolo = path.resolve(__dirname, '../../cosmic-swingset/bin/ag-solo'); } else { - agSolo = `${process.cwd()}/node_modules/@agoric/cosmic-swingset/bin/ag-solo`; + agSolo = `/usr/src/dapp/${process.cwd()}/node_modules/@agoric/cosmic-swingset/bin/ag-solo`; } async function startFakeChain(profileName, _startArgs, popts) { const fakeDelay = popts.delay === undefined ? FAKE_CHAIN_DELAY : Number(popts.delay); + const agServer = `_agstate/agoric-servers/${profileName}`; + + if (popts.reset) { + log(chalk.green(`removing ${agServer}`)); + // rm is available on all the unix-likes, so use it for speed. + await pspawn('rm', ['-rf', agServer]); + } + if (!opts.sdk) { if ( !(await exists('node_modules/@agoric/cosmic-swingset')) && @@ -168,36 +178,30 @@ export default async function startMain(progname, rawArgs, powers, opts) { } async function startLocalChain(profileName, startArgs, popts) { - const IMAGE = `agoric/agoric-sdk`; - const portNum = startArgs[0] === undefined ? CHAIN_PORT : startArgs[0]; if (`${portNum}` !== `${Number(portNum)}`) { log.error(`Argument to local-chain must be a port number`); return 1; } - const localAgServer = `${agServer}-${portNum}`; if (popts.pull) { - const exitStatus = await pspawn('docker', ['pull', IMAGE]); + const exitStatus = await pspawn('docker', ['pull', SDK_IMAGE]); if (exitStatus) { return exitStatus; } } + const agServer = `_agstate/agoric-servers/${profileName}-${portNum}`; if (popts.reset) { - log(chalk.green(`removing ${localAgServer}`)); + log(chalk.green(`removing ${agServer}`)); // rm is available on all the unix-likes, so use it for speed. - await pspawn('rm', ['-rf', localAgServer]); + await pspawn('rm', ['-rf', agServer]); } let chainSpawn; if (popts.sdk) { chainSpawn = (args, spawnOpts = undefined) => - pspawn( - 'ag-chain-cosmos', - [...args, `--home=${localAgServer}`], - spawnOpts, - ); + pspawn('ag-chain-cosmos', [...args, `--home=${agServer}`], spawnOpts); } else { chainSpawn = (args, spawnOpts = undefined, dockerArgs = []) => pspawn( @@ -208,15 +212,15 @@ export default async function startMain(progname, rawArgs, powers, opts) { `--rm`, ...dockerArgs, `-it`, - IMAGE, + SDK_IMAGE, ...args, - `--home=/usr/src/dapp/${localAgServer}`, + `--home=/usr/src/dapp/${agServer}`, ], spawnOpts, ); } - if (!(await exists(localAgServer))) { + if (!(await exists(agServer))) { const exitStatus = await chainSpawn([ 'init', 'local-chain', @@ -252,7 +256,7 @@ export default async function startMain(progname, rawArgs, powers, opts) { /* eslint-enable no-await-in-loop */ } - const genesisFile = `${localAgServer}/config/genesis.json`; + const genesisFile = `${agServer}/config/genesis.json`; if (!(await exists(`${genesisFile}.stamp`))) { let exitStatus; exitStatus = await chainSpawn([ @@ -302,7 +306,7 @@ export default async function startMain(progname, rawArgs, powers, opts) { // Complete the genesis file and launch the chain. log('read ag-chain-cosmos config'); - const configFile = `${localAgServer}/config/config.toml`; + const configFile = `${agServer}/config/config.toml`; const [genesisJson, configToml] = await Promise.all([ fs.readFile(genesisFile, 'utf-8'), fs.readFile(configFile, 'utf-8'), @@ -339,31 +343,30 @@ export default async function startMain(progname, rawArgs, powers, opts) { env: { ...pspawnEnv, ROLE: 'two_chain' }, }, // Accessible via either localhost or host.docker.internal - [`--publish=${portNum}:${portNum}`, `--name=agoric/n0`], + [`--publish=127.0.0.1:${portNum}:${portNum}`, `--name=agoric-n0`], ); } async function startLocalSolo(profileName, startArgs, popts) { - const IMAGE = `agoric/agoric-sdk`; - const portNum = startArgs[0] === undefined ? PORT : startArgs[0]; if (`${portNum}` !== `${Number(portNum)}`) { log.error(`Argument to local-solo must be a port number`); return 1; } - const localAgServer = `${agServer}-${portNum}`; + + const agServer = `_agstate/agoric-servers/${profileName}-${portNum}`; if (popts.pull) { - const exitStatus = await pspawn('docker', ['pull', IMAGE]); + const exitStatus = await pspawn('docker', ['pull', SDK_IMAGE]); if (exitStatus) { return exitStatus; } } if (popts.reset) { - log(chalk.green(`removing ${localAgServer}`)); + log(chalk.green(`removing ${agServer}`)); // rm is available on all the unix-likes, so use it for speed. - await pspawn('rm', ['-rf', localAgServer]); + await pspawn('rm', ['-rf', agServer]); } let soloSpawn; @@ -377,13 +380,13 @@ export default async function startMain(progname, rawArgs, powers, opts) { [ 'run', `--volume=${process.cwd()}:/usr/src/dapp`, + `--volume=${process.env.HOME}/.agoric:/root/.agoric`, + `-eAG_SOLO_BASEDIR=/usr/src/dapp/${agServer}`, `--rm`, - ...dockerArgs, `-it`, - `--entrypoint=${agSolo}`, + `--entrypoint=/usr/src/app/bin/ag-solo`, ...dockerArgs, - IMAGE, - `--home=/usr/src/dapp/${localAgServer}`, + SOLO_IMAGE, ...args, ], spawnOpts, @@ -391,12 +394,12 @@ export default async function startMain(progname, rawArgs, powers, opts) { } // Initialise the solo directory and key. - if (!(await exists(localAgServer))) { + if (!(await exists(agServer))) { const initArgs = [`--webport=${portNum}`]; if (!opts.sdk) { initArgs.push(`--webhost=0.0.0.0`); } - const exitStatus = await soloSpawn(['init', localAgServer, ...initArgs]); + const exitStatus = await soloSpawn(['init', ...initArgs]); if (exitStatus) { return exitStatus; } @@ -404,7 +407,7 @@ export default async function startMain(progname, rawArgs, powers, opts) { const spawnOpts = {}; if (popts.sdk) { - spawnOpts.cwd = localAgServer; + spawnOpts.cwd = agServer; } const rpcAddrs = [`localhost:${CHAIN_PORT}`]; @@ -414,24 +417,14 @@ export default async function startMain(progname, rawArgs, powers, opts) { let exitStatus; - // Connect to the chain. - const gciFile = `_agstate/agoric-servers/local-chain-${CHAIN_PORT}/config/genesis.json.sha256`; - const gci = (await fs.readFile(gciFile, 'utf-8')).trimRight(); - exitStatus = await soloSpawn( - ['set-gci-ingress', `--chainID=${CHAIN_ID}`, gci, rpcAddrs.join(',')], - spawnOpts, - ); - if (exitStatus) { - return exitStatus; - } - // Provision the ag-solo, if necessary. const soloAddr = ( - await fs.readFile(`${localAgServer}/ag-cosmos-helper-address`, 'utf-8') + await fs.readFile(`${agServer}/ag-cosmos-helper-address`, 'utf-8') ).trimRight(); + let bestRpcAddr; for (const rpcAddr of rpcAddrs) { // eslint-disable-next-line no-await-in-loop - const egressNeeded = await keysSpawn([ + exitStatus = await keysSpawn([ 'query', 'swingset', 'egress', @@ -439,7 +432,7 @@ export default async function startMain(progname, rawArgs, powers, opts) { `--chain-id=${CHAIN_ID}`, `--node=tcp://${rpcAddr}`, ]); - if (egressNeeded) { + if (exitStatus) { // We need to provision our address. const capret = capture( keysSpawn, @@ -463,18 +456,20 @@ export default async function startMain(progname, rawArgs, powers, opts) { // eslint-disable-next-line no-await-in-loop exitStatus = await capret[0]; if (!exitStatus) { + const json = capret[1].replace(/^gas estimate: \d+$/m, ''); try { - const ret = JSON.parse(capret[1]); + const ret = JSON.parse(json); if (ret.code !== 0) { exitStatus = 2; } } catch (e) { - console.error(`Cannot parse JSON:`, e, capret[1]); + console.error(`Cannot parse JSON:`, e, json); exitStatus = 99; } } } if (!exitStatus) { + bestRpcAddr = rpcAddr; break; } } @@ -482,20 +477,39 @@ export default async function startMain(progname, rawArgs, powers, opts) { return exitStatus; } + // Connect to the chain. + const gciFile = `_agstate/agoric-servers/local-chain-${CHAIN_PORT}/config/genesis.json.sha256`; + const gci = (await fs.readFile(gciFile, 'utf-8')).trimRight(); + exitStatus = await soloSpawn( + ['set-gci-ingress', `--chainID=${CHAIN_ID}`, gci, bestRpcAddr], + spawnOpts, + ); + if (exitStatus) { + return exitStatus; + } + // Now actually start the solo. - return soloSpawn(['start'], spawnOpts, [`--publish=${portNum}:${portNum}`]); + return soloSpawn(['start'], spawnOpts, [ + `--publish=127.0.0.1:${portNum}:${portNum}`, + ]); } async function startTestnetDocker(profileName, startArgs, popts) { - const IMAGE = `agoric/cosmic-swingset-setup-solo`; - if (popts.pull) { - const exitStatus = await pspawn('docker', ['pull', IMAGE]); + const exitStatus = await pspawn('docker', ['pull', SOLO_IMAGE]); if (exitStatus) { return exitStatus; } } + const agServer = `_agstate/agoric-servers/${profileName}`; + + if (popts.reset) { + log(chalk.green(`removing ${agServer}`)); + // rm is available on all the unix-likes, so use it for speed. + await pspawn('rm', ['-rf', agServer]); + } + const setupRun = (...bonusArgs) => pspawn('docker', [ 'run', @@ -504,24 +518,25 @@ export default async function startMain(progname, rawArgs, powers, opts) { `-eAG_SOLO_BASEDIR=/usr/src/dapp/${agServer}`, `--rm`, `-it`, - IMAGE, + SOLO_IMAGE, `--webport=${PORT}`, `--webhost=0.0.0.0`, ...bonusArgs, ...startArgs, ]); - if (!(await exists(agServer))) { - const exitStatus = await setupRun('--no-restart'); - if (exitStatus) { - return exitStatus; - } - } - - return setupRun(); + return setupRun('setup'); } - async function startTestnetSdk(_profileName, startArgs) { + async function startTestnetSdk(profileName, startArgs, popts) { + const agServer = `_agstate/agoric-servers/${profileName}`; + + if (popts.reset) { + log(chalk.green(`removing ${agServer}`)); + // rm is available on all the unix-likes, so use it for speed. + await pspawn('rm', ['-rf', agServer]); + } + const setupRun = (...bonusArgs) => pspawn(agSolo, [`--webport=${PORT}`, ...bonusArgs, ...startArgs], { env: { ...pspawnEnv, AG_SOLO_BASEDIR: agServer }, @@ -561,13 +576,5 @@ export default async function startMain(progname, rawArgs, powers, opts) { return 1; } - agServer = `_agstate/agoric-servers/${profileName}`; - - if (popts.reset) { - log(chalk.green(`removing ${agServer}`)); - // rm is available on all the unix-likes, so use it for speed. - await pspawn('rm', ['-rf', agServer]); - } - return startFn(profileName, args[0] ? args.slice(1) : args, popts); }