Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getAllCompilerAbstracts method to compiler-artefacts.ts #1

Open
wants to merge 3 commits into
base: contract-verification-plugin-base-reviewing-base
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 46 additions & 68 deletions libs/remix-core-plugin/src/lib/compiler-artefacts.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,84 @@
'use strict'
import { Plugin } from '@remixproject/engine'
import { util } from '@remix-project/remix-lib'
import { CompilerAbstract } from '@remix-project/remix-solidity'
import {Plugin} from '@remixproject/engine'
import {util} from '@remix-project/remix-lib'
import {CompilerAbstract} from '@remix-project/remix-solidity'

const profile = {
name: 'compilerArtefacts',
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract'],
events: [],
version: '0.0.1'
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract', 'getAllCompilerAbstracts'],
events: ['compilationSaved'],
version: '0.0.1',
}

export class CompilerArtefacts extends Plugin {
compilersArtefactsPerFile: any
compilersArtefacts: any
constructor () {
constructor() {
super(profile)
this.compilersArtefacts = {}
this.compilersArtefactsPerFile = {}
}

clear () {
clear() {
this.compilersArtefacts = {}
this.compilersArtefactsPerFile = {}
}

saveCompilerAbstract (file: string, compilerAbstract: CompilerAbstract) {
saveCompilerAbstract(file: string, compilerAbstract: CompilerAbstract) {
this.compilersArtefactsPerFile[file] = compilerAbstract
}

onActivation () {
const saveCompilationPerFileResult = (file, source, languageVersion, data, input?) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this but took the function's contents to saveCompilationResult

getAllCompilerAbstracts() {
return this.compilersArtefactsPerFile
}
Comment on lines +31 to +33
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this function


onActivation() {
const saveCompilationResult = (file, source, languageVersion, data, input?) => {
this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input)
this.compilersArtefacts.__last = this.compilersArtefactsPerFile[file]
Comment on lines 37 to +38
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the contents of listener functions to this single function called saveCompilationResult. This also contains what the prev. saveCompilationPerFileResult has.

Basically we always pass the input to the CompilerAbstract constructor and then point this one as the __last artefact. Maybe we might want to create a separate new CompilerAbstract for __last but this seemed proper to me.e

this.emit('compilationSaved', {[file]: this.compilersArtefactsPerFile[file]})
}

this.on('solidity', 'compilationFinished', (file, source, languageVersion, data, input, version) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('solidity', 'compilationFinished', saveCompilationResult)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think saveCompilationResult can take at most 5 parameters

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it has 5 parameters?

const saveCompilationResult = (file, source, languageVersion, data, input?) => {
this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input)
this.compilersArtefacts.__last = this.compilersArtefactsPerFile[file]
}


this.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('vyper', 'compilationFinished', saveCompilationResult)

this.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('lexon', 'compilationFinished', saveCompilationResult)

this.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('yulp', 'compilationFinished', saveCompilationResult)

this.on('solidityUnitTesting', 'compilationFinished', (file, source, languageVersion, data, input, version) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input)
saveCompilationPerFileResult(file, source, languageVersion, data, input)
})
this.on('solidityUnitTesting', 'compilationFinished', saveCompilationResult)

this.on('nahmii-compiler', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('nahmii-compiler', 'compilationFinished', saveCompilationResult)

this.on('hardhat', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('hardhat', 'compilationFinished', saveCompilationResult)

this.on('truffle', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('truffle', 'compilationFinished', saveCompilationResult)

this.on('foundry', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
saveCompilationPerFileResult(file, source, languageVersion, data)
})
this.on('foundry', 'compilationFinished', saveCompilationResult)
}

/**
* Get artefacts for last compiled contract
* * @returns last compiled contract compiler abstract
*/
getLastCompilationResult () {
getLastCompilationResult() {
return this.compilersArtefacts.__last
}

/**
* Get compilation output for contracts compiled during a session of Remix IDE
* @returns compilatin output
*/
getAllContractDatas () {
getAllContractDatas() {
return this.filterAllContractDatas(() => true)
}

/**
* filter compilation output for contracts compiled during a session of Remix IDE
* @returns compilatin output
*/
filterAllContractDatas (filter) {
filterAllContractDatas(filter) {
const contractsData = {}
Object.keys(this.compilersArtefactsPerFile).map((targetFile) => {
const artefact = this.compilersArtefactsPerFile[targetFile]
Expand All @@ -124,7 +103,7 @@ export class CompilerArtefacts extends Plugin {
* @param contractName contract name
* @returns arefacts object, with fully qualified name (e.g; contracts/1_Storage.sol:Storage) as key
*/
_getAllContractArtefactsfromOutput (compilerOutput, contractName) {
_getAllContractArtefactsfromOutput(compilerOutput, contractName) {
const contractArtefacts = {}
for (const filename in compilerOutput) {
if (Object.keys(compilerOutput[filename]).includes(contractName)) contractArtefacts[filename + ':' + contractName] = compilerOutput[filename][contractName]
Expand All @@ -139,12 +118,12 @@ export class CompilerArtefacts extends Plugin {
* @param contractArtefacts populated resultant artefacts object, with fully qualified name (e.g: contracts/1_Storage.sol:Storage) as key
* Once method execution completes, contractArtefacts object will hold all possible artefacts for contract
*/
async _populateAllContractArtefactsFromFE (path, contractName, contractArtefacts) {
async _populateAllContractArtefactsFromFE(path, contractName, contractArtefacts) {
const dirList = await this.call('fileManager', 'dirList', path)
if (dirList && dirList.length) {
for (const dirPath of dirList) {
// check if directory contains an 'artifacts' folder and a 'build-info' folder inside 'artifacts'
if (dirPath === path + '/artifacts' && await this.call('fileManager', 'exists', dirPath + '/build-info')) {
if (dirPath === path + '/artifacts' && (await this.call('fileManager', 'exists', dirPath + '/build-info'))) {
const buildFileList = await this.call('fileManager', 'fileList', dirPath + '/build-info')
// process each build-info file to populate the artefacts for contractName
for (const buildFile of buildFileList) {
Expand All @@ -155,7 +134,7 @@ export class CompilerArtefacts extends Plugin {
// populate the resultant object with artefacts
Object.assign(contractArtefacts, artefacts)
}
} else await this._populateAllContractArtefactsFromFE (dirPath, contractName, contractArtefacts)
} else await this._populateAllContractArtefactsFromFE(dirPath, contractName, contractArtefacts)
}
} else return
}
Expand All @@ -165,31 +144,30 @@ export class CompilerArtefacts extends Plugin {
* @param name contract name or fully qualified name i.e. <filename>:<contractname> e.g: contracts/1_Storage.sol:Storage
* @returns artefacts for the contract
*/
async getArtefactsByContractName (name) {
async getArtefactsByContractName(name) {
const contractsDataByFilename = this.getAllContractDatas()
// check if name is a fully qualified name
if (name.includes(':')) {
const fullyQualifiedName = name
const nameArr = fullyQualifiedName.split(':')
const filename = nameArr[0]
const contract = nameArr[1]
if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract])
return contractsDataByFilename[filename][contract]
if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract]) return contractsDataByFilename[filename][contract]
else {
const allContractsData = {}
await this._populateAllContractArtefactsFromFE ('contracts', contract, allContractsData)
if (allContractsData[fullyQualifiedName]) return { fullyQualifiedName, artefact: allContractsData[fullyQualifiedName] }
await this._populateAllContractArtefactsFromFE('contracts', contract, allContractsData)
if (allContractsData[fullyQualifiedName]) return {fullyQualifiedName, artefact: allContractsData[fullyQualifiedName]}
else throw new Error(`Could not find artifacts for ${fullyQualifiedName}. Compile contract to generate artifacts.`)
}
} else {
const contractName = name
const contractArtefacts = this._getAllContractArtefactsfromOutput(contractsDataByFilename, contractName)
let keys = Object.keys(contractArtefacts)
if (!keys.length) {
await this._populateAllContractArtefactsFromFE ('contracts', contractName, contractArtefacts)
await this._populateAllContractArtefactsFromFE('contracts', contractName, contractArtefacts)
keys = Object.keys(contractArtefacts)
}
if (keys.length === 1) return { fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]] }
if (keys.length === 1) return {fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]]}
else if (keys.length > 1) {
throw new Error(`There are multiple artifacts for contract "${contractName}", please use a fully qualified name.\n
Please replace ${contractName} for one of these options wherever you are trying to read its artifact: \n
Expand All @@ -199,7 +177,7 @@ export class CompilerArtefacts extends Plugin {
}
}

async getCompilerAbstract (file) {
async getCompilerAbstract(file) {
if (!file) return null
if (this.compilersArtefactsPerFile[file]) return this.compilersArtefactsPerFile[file]
const path = await this.call('fileManager', 'getPathFromUrl', file)
Expand All @@ -215,30 +193,30 @@ export class CompilerArtefacts extends Plugin {
return artefact
}

addResolvedContract (address: string, compilerData: CompilerAbstract) {
addResolvedContract(address: string, compilerData: CompilerAbstract) {
this.compilersArtefacts[address] = compilerData
}

isResolved (address) {
isResolved(address) {
return this.compilersArtefacts[address] !== undefined
}

get (key) {
get(key) {
return this.compilersArtefacts[key]
}

async getContractDataFromAddress (address) {
async getContractDataFromAddress(address) {
const code = await this.call('blockchain', 'getCode', address)
return this.getContractDataFromByteCode(code)
}

async getContractDataFromByteCode (code) {
async getContractDataFromByteCode(code) {
let found
this.filterAllContractDatas((file, contractsData) => {
for (const name of Object.keys(contractsData)) {
const contract = contractsData[name]
if (util.compareByteCode(code, '0x' + contract.evm.deployedBytecode.object)) {
found = { name, contract, file }
found = {name, contract, file}
return true
}
}
Expand Down