Skip to content

Commit

Permalink
Throw an error if registry deploy fails
Browse files Browse the repository at this point in the history
  • Loading branch information
joewagner committed Aug 24, 2023
1 parent 6aee245 commit aa3783a
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 274 deletions.
80 changes: 53 additions & 27 deletions packages/local/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { type ChildProcess } from "node:child_process";
import { EventEmitter } from "node:events";
import spawn from "cross-spawn";
import shell from "shelljs";
import { getDefaultProvider } from "ethers";
import { chalk } from "./chalk.js";
import { ValidatorDev, ValidatorPkg } from "./validators.js";
import {
buildConfig,
type Config,
checkPortInUse,
defaultRegistryDir,
inDebugMode,
isValidPort,
Expand All @@ -22,11 +24,11 @@ import {
getValidator,
logSync,
pipeNamedSubprocess,
probePortInUse,
waitForReady,
} from "./util.js";

const spawnSync = spawn.sync;
const registryAddress = "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512";

class LocalTableland {
config;
Expand Down Expand Up @@ -62,7 +64,7 @@ class LocalTableland {
typeof config.registryDir === "string" &&
config.registryDir.trim() !== ""
) {
this.registryDir = config.registryDir;
this.registryDir = config.registryDir.trim();
} else {
this.registryDir = defaultRegistryDir();
}
Expand All @@ -80,19 +82,15 @@ class LocalTableland {
}

async #_start(config: Config = {}): Promise<void> {
if (
typeof this.registryDir !== "string" ||
this.registryDir.trim() === ""
) {
if (typeof this.registryDir !== "string" || this.registryDir === "") {
throw new Error("cannot start a local network without Registry");
}

// make sure we are starting fresh
// TODO: I don't think this is doing anything anymore...
this.#_cleanup();

// Check if the hardhat port is in use (defaults to 5 retries, 300ms b/w each try)
const registryPortIsTaken = await probePortInUse(this.registryPort);
const registryPortIsTaken = await checkPortInUse(this.registryPort);
// Note: this generally works, but there is a chance that the port will be
// taken but returns `false`. E.g., try racing two instances at *exactly*
// the same, and `EADDRINUSE` occurs. But generally, it'll work as expected.
Expand All @@ -101,14 +99,18 @@ class LocalTableland {
// Else, notify the user only if it's a not the default and is custom.
if (registryPortIsTaken) {
throw new Error(`port ${this.registryPort} already in use`);
} else {
// Notify that we're using a custom port since it's not the default 8545
}

// Notify that we're using a custom port since it's not the default 8545
if (
this.registryPort !== this.defaultRegistryPort &&
shell.echo(
`[${chalk.magenta.bold("Notice")}] Registry is using custom port ${
this.registryPort
}`
);
this.silent !== true
) {
shell.echo(
`[${chalk.magenta.bold("Notice")}] Registry is using custom port ${
this.registryPort
}`
);
}

// You *must* store these in `process.env` to access within the hardhat subprocess
Expand Down Expand Up @@ -149,17 +151,14 @@ class LocalTableland {
// wait until initialization is done
await waitForReady(registryReadyEvent, this.initEmitter);

// Deploy the Registry to the Hardhat node
logSync(
spawnSync(
isWindows() ? "npx.cmd" : "npx",
["hardhat", "run", "--network", "localhost", "scripts/deploy.ts"],
{
cwd: this.registryDir,
}
),
!inDebugMode()
);
this._deployRegistry();

const deployed = await this.#_ensureRegistry();
if (!deployed) {
throw new Error(
"deploying registry contract failed, cannot start network"
);
}

// Need to determine if we are starting the validator via docker
// and a local repo, or if are running a binary etc...
Expand All @@ -172,7 +171,7 @@ class LocalTableland {
// run this before starting in case the last instance of the validator didn't get cleanup after
// this might be needed if a test runner force quits the parent local-tableland process
this.validator.cleanup();
this.validator.start();
this.validator.start(registryAddress);

// TODO: It seems like this check isn't sufficient to see if the process is gonna get to a point
// where the on error listener can be attached.
Expand Down Expand Up @@ -220,6 +219,33 @@ class LocalTableland {
console.log("\n\n*************************************\n");
}

// note: Tests are using sinon to stub this method. Because typescript compiles ecmascript
// private features, i.e. hash syntax, in a way that does not work with sinon we must
// use the ts private modifier here in order to test the failure to deploy the registry.
private _deployRegistry(): void {
// Deploy the Registry to the Hardhat node
logSync(
spawnSync(
isWindows() ? "npx.cmd" : "npx",
["hardhat", "run", "--network", "localhost", "scripts/deploy.ts"],
{
cwd: this.registryDir,
}
),
!inDebugMode()
);
}

async #_ensureRegistry(): Promise<boolean> {
const provider = getDefaultProvider(
`http://127.0.0.1:${this.registryPort}`
);
const code = await provider.getCode(registryAddress);

// if the contract exists, and is not empty, code will not be equal to 0x
return code !== "0x";
}

async #_setReady(): Promise<void> {
this.ready = true;
while (this.#_readyResolves.length > 0) {
Expand Down
25 changes: 0 additions & 25 deletions packages/local/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,31 +402,6 @@ export async function checkPortInUse(port: number): Promise<boolean> {
});
}

/**
* Probe a port with retries to check if it is in use.
* @param port The port number.
* @param tries Number of retries to attempt. Defaults to 5.
* @param delay Time to wait between retries (in milliseconds). Defaults to 300.
* @returns true if the port is in use, false otherwise
*/
export async function probePortInUse(
port: number,
tries: number = 5,
delay: number = 300
): Promise<boolean> {
let numTries = 0;
while (numTries < tries) {
// Note: consider splitting the delay into before and after this check
// Racing two instances might cause this to incorrectly return `false`
const portIsTaken = await checkPortInUse(port);
if (!portIsTaken) return false;

await new Promise((resolve) => setTimeout(resolve, delay));
numTries++;
}
return true;
}

const hardhatAccounts = [
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
"59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
Expand Down
10 changes: 6 additions & 4 deletions packages/local/src/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ValidatorPkg {
}
}

start(): void {
start(registryAddress?: string): void {
const binPath = getBinPath();
if (binPath == null) {
throw new Error(
Expand Down Expand Up @@ -141,7 +141,10 @@ class ValidatorDev {
}
}

start(): void {
start(registryAddress?: string): void {
if (typeof registryAddress !== "string") {
throw new Error("must provide registry address");
}
// Add the registry address to the Validator config
// TODO: when https://github.com/tablelandnetwork/go-tableland/issues/317 is
// resolved we may be able to refactor a lot of this
Expand Down Expand Up @@ -169,8 +172,7 @@ class ValidatorDev {
// TODO: this could be parsed out of the deploy process, but since
// it's always the same address just hardcoding it here
// TODO: maybe we can get this from evm-tableland?
validatorConfig.Chains[0].Registry.ContractAddress =
"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512";
validatorConfig.Chains[0].Registry.ContractAddress = registryAddress;

writeFileSync(configFilePath, JSON.stringify(validatorConfig, null, 2));

Expand Down
Loading

0 comments on commit aa3783a

Please sign in to comment.