Ensure Hyperlane logging is always visible (#39)

- Setup consistent logging via debug-js
- DRY up script boilerplate
- Add more logging during deployments
pull/42/head
J M Rossy 2 years ago committed by GitHub
parent 6ad30c0061
commit 081db0337d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .eslintrc
  2. 8
      README.md
  3. 8
      ci.sh
  4. 18
      scripts/deploy-hyperlane.ts
  5. 18
      scripts/deploy-warp-routes.ts
  6. 11
      scripts/run.ts
  7. 15
      scripts/seed-phrase-to-pk.ts
  8. 29
      scripts/test-messages.ts
  9. 26
      scripts/test-warp-transfer.ts
  10. 13
      src/core/HyperlanePermissionlessDeployer.ts
  11. 22
      src/logger.ts
  12. 15
      src/warp/WarpRouteDeployer.ts

@ -18,6 +18,7 @@
"prettier"
],
"rules": {
"no-console": ["error"],
"no-eval": ["error"],
"no-extra-boolean-cast": ["error"],
"no-ex-assign": ["error"],

@ -36,7 +36,7 @@ This script also deploys the following contracts to all chains, new and existing
- `TestRecipient`: used to test that interchain messages can be delivered
```bash
DEBUG=hyperlane* yarn ts-node script scripts/deploy-hyperlane.ts --local anvil \
yarn ts-node scripts/deploy-hyperlane.ts --local anvil \
--remotes goerli sepolia \
--key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```
@ -48,7 +48,7 @@ This script is used to verify that Hyperlane messages can be sent between specif
Users should have first deployed `TestRecipient` contracts to each of the specified chains.
```sh
DEBUG=hyperlane* yarn ts-node scripts/test-messages.ts \
yarn ts-node scripts/test-messages.ts \
--chains anvil goerli sepolia \
--key 0x6f0311f4a0722954c46050bb9f088c4890999e16b64ad02784d24b5fd6d09061
```
@ -66,14 +66,14 @@ Establishing a warp route requires deployment of `HypERC20` contracts to the des
The deployment also require details about the existing (collateral) token and the new synthetics that will be created. Ensure there are entries for them in `config/warp_tokens.ts`.
```sh
DEBUG=hyperlane* yarn ts-node scripts/deploy-warp-routes.ts \
yarn ts-node scripts/deploy-warp-routes.ts \
--key 0x6f0311f4a0722954c46050bb9f088c4890999e16b64ad02784d24b5fd6d09061
```
### Sending a test transfer
```sh
DEBUG=hyperlane* yarn ts-node scripts/test-warp-transfer.ts \
yarn ts-node scripts/test-warp-transfer.ts \
--origin goerli --destination alfajores --wei 100000000000000 \
--key 0x6f0311f4a0722954c46050bb9f088c4890999e16b64ad02784d24b5fd6d09061
```

@ -21,12 +21,12 @@ for i in "anvil1 anvil2 --no-write-agent-config" "anvil2 anvil1 --write-agent-co
do
set -- $i
echo "Deploying contracts to $1"
DEBUG=hyperlane* yarn ts-node scripts/deploy-hyperlane.ts --local $1 --remotes $2 \
yarn ts-node scripts/deploy-hyperlane.ts --local $1 --remotes $2 \
--key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 $3
done
echo "Deploying warp routes"
DEBUG=hyperlane* yarn ts-node scripts/deploy-warp-routes.ts \
yarn ts-node scripts/deploy-warp-routes.ts \
--key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
kill $ANVIL_1_PID
@ -92,11 +92,11 @@ do
done
echo "Testing message sending"
DEBUG=hyperlane* yarn ts-node scripts/test-messages.ts --chains anvil1 anvil2 \
yarn ts-node scripts/test-messages.ts --chains anvil1 anvil2 \
--key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --timeout 60
echo "Sending a test warp transfer"
DEBUG=hyperlane* yarn ts-node scripts/test-warp-transfer.ts \
yarn ts-node scripts/test-warp-transfer.ts \
--origin anvil1 --destination anvil2 --wei 1 --recipient 0xac0974bec39a17e36ba4a6b4d238ff944bacb4a5 \
--key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --timeout 60

@ -1,15 +1,11 @@
import { HyperlanePermissionlessDeployer } from '../src/core/HyperlanePermissionlessDeployer';
import { logger } from '../src/logger';
async function main() {
console.info('Preparing Hyperlane deployer');
import { run } from './run';
run('Hyperlane deployment', async () => {
logger('Preparing Hyperlane deployer');
const deployer = await HyperlanePermissionlessDeployer.fromArgs();
console.info('Beginning Hyperlane deployment');
logger('Beginning Hyperlane deployment');
await deployer.deploy();
}
main()
.then(() => console.info('Hyperlane deployment completed successfully'))
.catch((e) => {
console.error('Error deploying Hyperlane', e);
process.exit(1);
});
});

@ -1,15 +1,11 @@
import { logger } from '../src/logger';
import { WarpRouteDeployer } from '../src/warp/WarpRouteDeployer';
async function main() {
console.info('Preparing Warp Route deployer');
import { run } from './run';
run('Warp route deployment', async () => {
logger('Preparing Warp Route deployer');
const deployer = await WarpRouteDeployer.fromArgs();
console.info('Beginning warp route deployment');
logger('Beginning warp route deployment');
await deployer.deploy();
}
main()
.then(() => console.info('Warp Routes deployed successfully'))
.catch((e) => {
console.error('Error deploying Warp Routes', e);
process.exit(1);
});
});

@ -0,0 +1,11 @@
import { error, logger } from '../src/logger';
export function run(name: string, fn: () => Promise<any>) {
logger(`Beginning ${name} script`);
fn()
.then(() => logger(`${name} completed successfully`))
.catch((e: any) => {
error(`Error running ${name}`, e);
process.exit(1);
});
}

@ -1,18 +1,17 @@
import { ethers } from 'ethers';
import yargs from 'yargs';
async function main() {
import { logger } from '../src/logger';
import { run } from './run';
run('Seed phrase to private key', async () => {
const { seed } = await yargs(process.argv.slice(2))
.describe('seed', 'seed phrase to derive key from')
.string('seed')
.demandOption('seed').argv;
const wallet = ethers.Wallet.fromMnemonic(seed);
console.log('Wallet private key:\n============');
console.log(wallet.privateKey);
}
main().catch((err) => {
console.error(err);
process.exit(1);
logger('Wallet private key:\n============');
logger(wallet.privateKey);
});

@ -25,6 +25,12 @@ import {
getMultiProvider,
mergedContractAddresses,
} from '../src/config';
import { createLogger } from '../src/logger';
import { run } from './run';
const logger = createLogger('MessageDeliveryTest');
const error = createLogger('MessageDeliveryTest', true);
function getArgs(multiProvider: MultiProvider) {
// Only accept chains for which we have both a connection and contract addresses
@ -71,7 +77,7 @@ function igpFromAddressesMap(
return new HyperlaneIgp(contractsMap, multiProvider);
}
async function main() {
run('Message delivery test', async () => {
let timedOut = false;
const multiProvider = getMultiProvider();
const { chains, key, timeout } = await getArgs(multiProvider);
@ -105,7 +111,7 @@ async function main() {
const dispatchedMessages = core.getDispatchedMessages(messageReceipt);
if (dispatchedMessages.length !== 1) continue;
const dispatchedMessage = dispatchedMessages[0];
console.log(
logger(
`Sent message from ${origin} to ${recipient} on ${destination} with message ID ${dispatchedMessage.id}`,
);
// Make gas payment...
@ -124,10 +130,10 @@ async function main() {
await paymentTx.wait();
messages.add(dispatchedMessage);
} catch (e) {
console.error(
error(
`Encountered error sending message from ${origin} to ${destination}`,
);
console.error(e);
error(e);
}
}
}
@ -141,13 +147,13 @@ async function main() {
const delivered = await mailbox.delivered(message.id);
if (delivered) {
messages.delete(message);
console.log(
logger(
`Message from ${origin} to ${destination} with ID ${
message!.id
} was delivered`,
);
} else {
console.log(
logger(
`Message from ${origin} to ${destination} with ID ${
message!.id
} has not yet been delivered`,
@ -158,14 +164,7 @@ async function main() {
}
clearTimeout(timeoutId);
if (timedOut) {
console.error('Timed out waiting for messages to be delivered');
error('Timed out waiting for messages to be delivered');
process.exit(1);
}
}
main()
.then(() => console.info('Testing complete'))
.catch((e) => {
console.error(e);
process.exit(1);
});
});

@ -33,8 +33,14 @@ import {
mergedContractAddresses,
} from '../src/config';
import { readJSONAtPath } from '../src/json';
import { createLogger } from '../src/logger';
import { WarpRouteArtifacts } from '../src/warp/WarpRouteDeployer';
import { run } from './run';
const logger = createLogger('WarpTransferTest');
const error = createLogger('WarpTransferTest', true);
function coreFromAddressesMap(
addressesMap: HyperlaneAddressesMap<CoreFactories>,
_multiProvider: MultiProvider,
@ -108,8 +114,7 @@ function hypErc20FromAddressesMap(
return new HypERC20App(contractsMap, multiProvider);
}
// TODO DRY up with test-messages script
async function main() {
run('Warp transfer test', async () => {
let timedOut = false;
const multiProvider = getMultiProvider();
const { recipient, origin, destination, wei, key, timeout } = await getArgs(
@ -208,29 +213,22 @@ async function main() {
!(await core.getContracts(destination).mailbox.delivered(message.id)) &&
!timedOut
) {
console.log(`Waiting for message delivery on destination chain`);
logger(`Waiting for message delivery on destination chain`);
await utils.sleep(1000);
}
if (!timedOut) {
console.log(`Message delivered on destination chain!`);
logger(`Message delivered on destination chain!`);
const balanceAfter = await getDestinationBalance();
if (!balanceAfter.gt(balanceBefore)) {
throw new Error('Destination chain balance did not increase');
}
console.log(`Confirmed balance increase`);
logger(`Confirmed balance increase`);
}
clearTimeout(timeoutId);
if (timedOut) {
console.error('Timed out waiting for messages to be delivered');
error('Timed out waiting for messages to be delivered');
process.exit(1);
}
}
main()
.then(() => console.info('Warp test transfer complete'))
.catch((e) => {
console.error(e);
process.exit(1);
});
});

@ -28,6 +28,7 @@ import {
getMultiProvider,
} from '../config';
import { mergeJSON, writeJSON } from '../json';
import { createLogger } from '../logger';
import {
HyperlaneTestRecipientDeployer,
@ -77,6 +78,7 @@ export class HyperlanePermissionlessDeployer {
public readonly local: ChainName,
public readonly remotes: ChainName[],
public readonly writeAgentConfig?: boolean,
protected readonly logger = createLogger('HyperlanePermissionlessDeployer'),
) {}
static async fromArgs(): Promise<HyperlanePermissionlessDeployer> {
@ -117,10 +119,12 @@ export class HyperlanePermissionlessDeployer {
coreConfig,
);
const coreContracts: HyperlaneContractsMap<CoreFactories> = {};
this.logger(`Deploying core contracts to local chain ${this.local}`);
coreContracts[this.local] = await coreDeployer.deployContracts(
this.local,
coreConfig[this.local],
);
this.logger(`Deployment of core contracts complete`);
contracts = objMerge(contracts, coreContracts);
// Next, deploy MultisigIsms to the remote chains
@ -130,9 +134,11 @@ export class HyperlanePermissionlessDeployer {
multisigIsm: coreContracts[this.local].multisigIsm,
};
for (const remote of this.remotes) {
this.logger(`Deploying multisig ISM to chain ${remote}`);
isms[remote] = {
multisigIsm: await coreDeployer.deployLegacyMultisigIsm(remote),
};
this.logger(`Deployment of multisig ISM to chain ${remote} complete`);
}
contracts = objMerge(contracts, isms);
@ -143,11 +149,14 @@ export class HyperlanePermissionlessDeployer {
return { ism: ism.multisigIsm.address };
},
);
this.logger(`Deploying test recipient`);
const testRecipientDeployer = new HyperlaneTestRecipientDeployer(
this.multiProvider,
testRecipientConfig,
);
const testRecipients = await testRecipientDeployer.deploy();
this.logger(`Test recipient deployment complete`);
contracts = objMerge(contracts, testRecipients);
// Finally, deploy IGPs to all chains
@ -159,7 +168,7 @@ export class HyperlanePermissionlessDeployer {
contracts = objMerge(contracts, igps);
const addresses = serializeContractsMap(contracts);
// Write contract address artifacts
this.logger(`Writing contract addresses to artifacts/addresses.json`);
mergeJSON('./artifacts/', 'addresses.json', addresses);
startBlocks[this.local] = await this.multiProvider
@ -173,7 +182,7 @@ export class HyperlanePermissionlessDeployer {
startBlocks,
);
// Write AgentConfig artifacts
this.logger(`Writing agent config to artifacts/agent_config.json`);
writeJSON('./artifacts/', 'agent_config.json', agentConfig);
}
}

@ -0,0 +1,22 @@
/* eslint-disable no-console */
import debug from 'debug';
const HYPERLANE_NS = 'hyperlane';
// Default root logger for use in utils/scripts
export const logger = debug(HYPERLANE_NS);
export const error = debug(`${HYPERLANE_NS}:ERROR`);
export function createLogger(namespace: string, isError = false) {
return isError ? error.extend(namespace) : logger.extend(namespace);
}
// Ensure hyperlane logging is enabled
const activeNamespaces = debug.disable();
const otherNamespaces = activeNamespaces
.split(',')
.filter((ns) => ns.includes(HYPERLANE_NS));
const hypNamespaces = `${HYPERLANE_NS},${HYPERLANE_NS}:*`;
debug.enable(
otherNamespaces ? `${otherNamespaces},${hypNamespaces}` : `${hypNamespaces}`,
);

@ -1,4 +1,3 @@
import debug from 'debug';
import { ethers } from 'ethers';
import yargs from 'yargs';
@ -27,6 +26,7 @@ import {
mergedContractAddresses,
} from '../config';
import { mergeJSON, tryReadJSON, writeJSON } from '../json';
import { createLogger } from '../logger';
import { getWarpConfigChains, validateWarpTokenConfig } from './config';
@ -51,7 +51,7 @@ export class WarpRouteDeployer {
constructor(
public readonly multiProvider: MultiProvider,
public readonly signer: ethers.Signer,
protected readonly logger = debug('hyperlane:WarpRouteDeployer'),
protected readonly logger = createLogger('WarpRouteDeployer'),
) {}
static async fromArgs(): Promise<WarpRouteDeployer> {
@ -65,12 +65,14 @@ export class WarpRouteDeployer {
async deploy(): Promise<void> {
const { configMap, baseToken } = await this.buildHypERC20Config();
this.logger('Initiating HypERC20 deployments');
const deployer = new HypERC20Deployer(
this.multiProvider,
configMap,
undefined,
);
await deployer.deploy();
this.logger('HypERC20 deployments complete');
this.writeDeploymentResult(
deployer.deployedContracts,
@ -144,6 +146,7 @@ export class WarpRouteDeployer {
chainMetadata.ethereum.nativeToken!
);
} else if (type === TokenType.collateral || type === TokenType.synthetic) {
this.logger(`Fetching token metadata for ${address} on ${chain}}`);
const provider = this.multiProvider.getProvider(chain);
const erc20Contract = ERC20__factory.connect(address, provider);
const [name, symbol, decimals] = await Promise.all([
@ -179,7 +182,9 @@ export class WarpRouteDeployer {
tokenConfigs: ChainMap<HypERC20Config>,
contracts: HyperlaneContractsMap<HypERC20Factories>,
) {
this.logger('Writing token deployment artifacts');
this.logger(
'Writing token deployment addresses to artifacts/warp-token-addresses.json',
);
const artifacts: ChainMap<WarpRouteArtifacts> = objMap(
contracts,
(chain, contract) => {
@ -198,7 +203,9 @@ export class WarpRouteDeployer {
baseTokenMetadata: TokenMetadata,
contracts: HyperlaneContractsMap<HypERC20Factories>,
) {
this.logger('Writing token list for warp ui');
this.logger(
'Writing warp ui token list to artifacts/warp-ui-token-list.json',
);
const currentTokenList = tryReadJSON(
'./artifacts/',
'warp-tokens.json',

Loading…
Cancel
Save