Skip to content

Commit

Permalink
Stop using await in loops
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaStebaev committed Sep 15, 2023
1 parent 1f1bca3 commit bf9a9c1
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 77 deletions.
1 change: 0 additions & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ module.exports = {
"never"
],

"no-await-in-loop": "warn",
"no-console": "warn",
"no-continue": "warn",
"no-duplicate-imports": "warn",
Expand Down
35 changes: 29 additions & 6 deletions src/contractFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,41 @@ const getSkaleManifest = async () => {
return manifest as SkaleManifestData;
};

const loadBytesCodes = async (libraryNames: string[]) => {
const byteCodes = new Map<string, string>();

(await Promise.
all(libraryNames.map((libraryName) => (async () => {
const {bytecode} = await artifacts.readArtifact(libraryName);
return [
libraryName,
bytecode
];
})()))).forEach(([
libraryName,
bytecode
]) => {
byteCodes.set(
libraryName,
bytecode
);
});
return byteCodes;
};

const updateManifest = async (
manifest: SkaleManifestData,
libraries: Map<string, string>,
oldLibraries: {[k: string]: string}
) => {
const byteCodes = await loadBytesCodes(Array.from(libraries.keys()));
for (const [
libraryName,
libraryAddress
] of libraries.entries()) {
const {bytecode} = await artifacts.readArtifact(libraryName);
manifest.libraries[libraryName] = {
"address": libraryAddress,
"bytecodeHash": hashBytecode(bytecode)
"bytecodeHash": hashBytecode(byteCodes.get(libraryName) as string)
};
}
Object.assign(
Expand Down Expand Up @@ -88,13 +110,14 @@ const getLibrariesToUpgrade = async (
) => {
const librariesToUpgrade = [];
const oldLibraries: {[k: string]: string} = {};
for (const libraryName of getLibrariesNames(linkReferences)) {
const {bytecode} = await artifacts.readArtifact(libraryName);
const librariesNames = getLibrariesNames(linkReferences);
const byteCodes = await loadBytesCodes(librariesNames);
for (const libraryName of librariesNames) {
if (manifest.libraries[libraryName] === undefined) {
librariesToUpgrade.push(libraryName);
} else if (
hashBytecode(bytecode) !== manifest.libraries[libraryName].
bytecodeHash
hashBytecode(byteCodes.get(libraryName) as string) !==
manifest.libraries[libraryName].bytecodeHash
) {
librariesToUpgrade.push(libraryName);
} else {
Expand Down
55 changes: 42 additions & 13 deletions src/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,34 @@ interface LibraryArtifacts {
[key: string]: unknown
}

const _deployLibrary = async (libraryName: string) => {
const
Library = await ethers.getContractFactory(libraryName);
const library = await Library.deploy();
const deployLibrary = async (libraryName: string, nonce: number) => {
const Library = await ethers.getContractFactory(libraryName);
const library = await Library.deploy({nonce});
await library.deployed();
return library.address;
};

export const deployLibraries = async (libraryNames: string[]) => {
const [deployer] = await ethers.getSigners();
const nonce = await deployer.getTransactionCount();
const libraries = new Map<string, string>();
for (const libraryName of libraryNames) {

(await Promise.all(libraryNames.map((libraryName, index) => (async () => [
libraryName,
await deployLibrary(
libraryName,
nonce + index
)
])()))).forEach(([
libraryName,
libraryAddress
]) => {
libraries.set(
libraryName,
await _deployLibrary(libraryName)
libraryAddress
);
}
});

return libraries;
};

Expand Down Expand Up @@ -101,16 +113,33 @@ const updateManifest = async (libraryArtifacts: LibraryArtifacts) => {

const getLibraryArtifacts = async (libraries: Map<string, string>) => {
const libraryArtifacts: LibraryArtifacts = {};
for (const [
libraryName,
libraryAddress
] of libraries.entries()) {

const getLibraryArtifact = async (
libraryName: string,
libraryAddress: string
) => {
const {bytecode} = await artifacts.readArtifact(libraryName);
libraryArtifacts[libraryName] = {
return {
"address": libraryAddress,
"bytecodeHash": hashBytecode(bytecode)
"bytecodeHash": hashBytecode(bytecode),
libraryName
};
};

for (const libraryArtifact of await Promise.
all(Array.from(libraries.entries()).map(([
libraryName,
libraryAddress
]) => getLibraryArtifact(
libraryName,
libraryAddress
)))) {
libraryArtifacts[libraryArtifact.libraryName] = {
"address": libraryArtifact.address,
"bytecodeHash": libraryArtifact.bytecodeHash
};
}

return libraryArtifacts;
};

Expand Down
28 changes: 14 additions & 14 deletions src/gnosis-safe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,20 @@ const estimateSafeTransaction = async (
) => {
console.log("Estimate gas");
const safeService = await getSafeService();
for (const transaction of safeTransactionData as MetaTransactionData[]) {
const estimateResponse = await safeService.estimateSafeTransaction(
safeAddress,
{
"to": transaction.to,
"value": transaction.value,
"data": transaction.data,
"operation": transaction.operation || 0
}
);
console.log(chalk.cyan(`Recommend to set gas limit to ${parseInt(
estimateResponse.safeTxGas,
10
)}`));
const gasEstimations = await Promise.
all((safeTransactionData as MetaTransactionData[]).
map((transaction) => safeService.estimateSafeTransaction(
safeAddress,
{
"to": transaction.to,
"value": transaction.value,
"data": transaction.data,
"operation": transaction.operation || 0
}
)));
for (const estimateResponse of gasEstimations) {
console.log(chalk.cyan("Recommend to set gas limit" +
` to ${estimateResponse.safeTxGas}`));
}
console.log(chalk.green("Send transaction to gnosis safe"));
};
Expand Down
26 changes: 14 additions & 12 deletions src/submitters/eoa-submitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ export class EoaSubmitter extends Submitter {
async submit (transactions: UnsignedTransaction[]) {
EoaSubmitter._atomicityWarning();
const [deployer] = await ethers.getSigners();
for (const transaction of transactions) {
console.log(`Send transaction via ${this.name}`);
const response = await deployer.sendTransaction({
"to": transaction.to,
"value": transaction.value,
"data": transaction.data
});
console.log("Waiting for a transaction" +
` with nonce ${response.nonce}`);
await response.wait();
console.log("The transaction was sent");
}
const nonce = await deployer.getTransactionCount();
console.log(`Send transaction via ${this.name}`);
const responses =
await Promise.all(transactions.
map((transaction, index) => deployer.sendTransaction({
"to": transaction.to,
"value": transaction.value,
"data": transaction.data,
"nonce": nonce + index
})));

console.log("Waiting for transactions");
await Promise.all(responses.map((response) => response.wait()));
console.log("The transactions were sent");
}
}
18 changes: 9 additions & 9 deletions src/submitters/safe-ima-legacy-marionette-submitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,9 @@ export class SafeImaLegacyMarionetteSubmitter extends SafeToImaSubmitter {
if (transactions.length > 1) {
SafeImaLegacyMarionetteSubmitter._atomicityWarning();
}
const transactionsToMarionette = [];
for (const transaction of transactions) {
transactionsToMarionette.push({
"to": this.marionette.address,
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
"data": await this.marionette.encodeFunctionCall(
const transactionsToMarionette =
(await Promise.all(transactions.
map((transaction) => this.marionette.encodeFunctionCall(
transaction.to
? transaction.to
: ethers.constants.AddressZero,
Expand All @@ -59,9 +56,12 @@ export class SafeImaLegacyMarionetteSubmitter extends SafeToImaSubmitter {
transaction.data
? transaction.data
: "0x"
) as BytesLike
});
}
) as Promise<BytesLike>))
).map((data) => ({
data,
"to": this.marionette.address
}));

await super.submit(transactionsToMarionette);
}
}
28 changes: 12 additions & 16 deletions src/upgrader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ interface Target {
contractNamesToUpgrade: string[]
}

const withoutUndefined = <T>(array: Array<T | undefined>) => array.
filter((element) => element !== undefined) as Array<T>;


export abstract class Upgrader {
instance: Instance;

Expand Down Expand Up @@ -137,13 +141,11 @@ export abstract class Upgrader {
console.log("Skip verification");
} else {
console.log("Start verification");
for (const contract of contractsToUpgrade) {
await verify(
contract.name,
contract.implementationAddress,
[]
);
}
await Promise.all(contractsToUpgrade.map((contract) => verify(
contract.name,
contract.implementationAddress,
[]
)));
}
}

Expand Down Expand Up @@ -171,15 +173,9 @@ export abstract class Upgrader {
}

private async deployNewImplementations () {
const contractsToUpgrade: ContractToUpgrade[] = [];
for (const contract of this.contractNamesToUpgrade) {
const updatedContract =
await this.deployNewImplementation(contract);
if (updatedContract !== undefined) {
contractsToUpgrade.push(updatedContract);
}
}
return contractsToUpgrade;
const contracts = await Promise.all(this.contractNamesToUpgrade.
map(this.deployNewImplementation));
return withoutUndefined(contracts);
}

private async deployNewImplementation (contract: string) {
Expand Down
35 changes: 29 additions & 6 deletions src/verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,30 @@ const verificationAttempt = async (
return false;
};

interface VerificationTarget {
contractName: string;
contractAddress: string;
constructorArguments: object;
}

const verifyWithRetry = async (
verificationTarget: VerificationTarget,
attempts: number
) => {
if (attempts > 0) {
if (!await verificationAttempt(
verificationTarget.contractName,
verificationTarget.contractAddress,
verificationTarget.constructorArguments
)) {
await verifyWithRetry(
verificationTarget,
attempts - 1
);
}
}
};

export const verify = async (
contractName: string,
contractAddress: string,
Expand All @@ -60,15 +84,14 @@ export const verify = async (
console.log(chalk.grey(errorMessage));
return;
}
for (let retry = 0; retry <= 5; retry += 1) {
if (await verificationAttempt(
await verifyWithRetry(
{
contractName,
contractAddress,
constructorArguments
)) {
break;
}
}
},
5
);
};

export const verifyProxy = async (
Expand Down

0 comments on commit bf9a9c1

Please sign in to comment.