Skip to content

Commit a148a7f

Browse files
committed
Add getAllCompilerAbstracts method to compiler-artefacts.ts
The current compilerArtefacts plugin's existing methods had two flaws: 1. It wasn't possible to get all Compiler Abstracts available in one go. 2. It was possible to first get all files with `getAllContractsData` and then call each CompilerAbstract one by one with `getCompilerAbstract`, however, in that case the CompilerAbstract was missing the `input` because it wasn't passed to the contructor and saveCompilationPerFileResult. It was only done so for the `solidityUnitTesting` plugin listener. The compiler input is needed for consistent contract verification. While it's possible to generate a compiler input from the contract artefact, via the metadata, it is not always possible to get a match due to known bugs in compiler's AST generation in prev. versions. This results in different bytecode from the original compiler input's output vs the compilation output from the metadata file.
1 parent 3ffb8fa commit a148a7f

File tree

1 file changed

+44
-67
lines changed

1 file changed

+44
-67
lines changed

libs/remix-core-plugin/src/lib/compiler-artefacts.ts

Lines changed: 44 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,83 @@
11
'use strict'
2-
import { Plugin } from '@remixproject/engine'
3-
import { util } from '@remix-project/remix-lib'
4-
import { CompilerAbstract } from '@remix-project/remix-solidity'
2+
import {Plugin} from '@remixproject/engine'
3+
import {util} from '@remix-project/remix-lib'
4+
import {CompilerAbstract} from '@remix-project/remix-solidity'
55

66
const profile = {
77
name: 'compilerArtefacts',
8-
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract'],
8+
methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract', 'getAllCompilerAbstracts'],
99
events: [],
10-
version: '0.0.1'
10+
version: '0.0.1',
1111
}
1212

1313
export class CompilerArtefacts extends Plugin {
1414
compilersArtefactsPerFile: any
1515
compilersArtefacts: any
16-
constructor () {
16+
constructor() {
1717
super(profile)
1818
this.compilersArtefacts = {}
1919
this.compilersArtefactsPerFile = {}
2020
}
2121

22-
clear () {
22+
clear() {
2323
this.compilersArtefacts = {}
2424
this.compilersArtefactsPerFile = {}
2525
}
2626

27-
saveCompilerAbstract (file: string, compilerAbstract: CompilerAbstract) {
27+
saveCompilerAbstract(file: string, compilerAbstract: CompilerAbstract) {
2828
this.compilersArtefactsPerFile[file] = compilerAbstract
2929
}
3030

31-
onActivation () {
32-
const saveCompilationPerFileResult = (file, source, languageVersion, data, input?) => {
31+
getAllCompilerAbstracts() {
32+
return this.compilersArtefactsPerFile
33+
}
34+
35+
onActivation() {
36+
const saveCompilationResult = (file, source, languageVersion, data, input?) => {
37+
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input)
3338
this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input)
3439
}
3540

36-
this.on('solidity', 'compilationFinished', (file, source, languageVersion, data, input, version) => {
37-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input)
38-
saveCompilationPerFileResult(file, source, languageVersion, data)
39-
})
41+
this.on('solidity', 'compilationFinished', saveCompilationResult)
4042

41-
this.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => {
42-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
43-
saveCompilationPerFileResult(file, source, languageVersion, data)
44-
})
43+
this.on('vyper', 'compilationFinished', saveCompilationResult)
4544

46-
this.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => {
47-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
48-
saveCompilationPerFileResult(file, source, languageVersion, data)
49-
})
45+
this.on('lexon', 'compilationFinished', saveCompilationResult)
5046

51-
this.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => {
52-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
53-
saveCompilationPerFileResult(file, source, languageVersion, data)
54-
})
47+
this.on('yulp', 'compilationFinished', saveCompilationResult)
5548

56-
this.on('solidityUnitTesting', 'compilationFinished', (file, source, languageVersion, data, input, version) => {
57-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input)
58-
saveCompilationPerFileResult(file, source, languageVersion, data, input)
59-
})
49+
this.on('solidityUnitTesting', 'compilationFinished', saveCompilationResult)
6050

61-
this.on('nahmii-compiler', 'compilationFinished', (file, source, languageVersion, data) => {
62-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
63-
saveCompilationPerFileResult(file, source, languageVersion, data)
64-
})
51+
this.on('nahmii-compiler', 'compilationFinished', saveCompilationResult)
6552

66-
this.on('hardhat', 'compilationFinished', (file, source, languageVersion, data) => {
67-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
68-
saveCompilationPerFileResult(file, source, languageVersion, data)
69-
})
53+
this.on('hardhat', 'compilationFinished', saveCompilationResult)
7054

71-
this.on('truffle', 'compilationFinished', (file, source, languageVersion, data) => {
72-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
73-
saveCompilationPerFileResult(file, source, languageVersion, data)
74-
})
55+
this.on('truffle', 'compilationFinished', saveCompilationResult)
7556

76-
this.on('foundry', 'compilationFinished', (file, source, languageVersion, data) => {
77-
this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source)
78-
saveCompilationPerFileResult(file, source, languageVersion, data)
79-
})
57+
this.on('foundry', 'compilationFinished', saveCompilationResult)
8058
}
8159

8260
/**
8361
* Get artefacts for last compiled contract
8462
* * @returns last compiled contract compiler abstract
8563
*/
86-
getLastCompilationResult () {
64+
getLastCompilationResult() {
8765
return this.compilersArtefacts.__last
8866
}
8967

9068
/**
9169
* Get compilation output for contracts compiled during a session of Remix IDE
9270
* @returns compilatin output
9371
*/
94-
getAllContractDatas () {
72+
getAllContractDatas() {
9573
return this.filterAllContractDatas(() => true)
9674
}
9775

9876
/**
9977
* filter compilation output for contracts compiled during a session of Remix IDE
10078
* @returns compilatin output
10179
*/
102-
filterAllContractDatas (filter) {
80+
filterAllContractDatas(filter) {
10381
const contractsData = {}
10482
Object.keys(this.compilersArtefactsPerFile).map((targetFile) => {
10583
const artefact = this.compilersArtefactsPerFile[targetFile]
@@ -124,7 +102,7 @@ export class CompilerArtefacts extends Plugin {
124102
* @param contractName contract name
125103
* @returns arefacts object, with fully qualified name (e.g; contracts/1_Storage.sol:Storage) as key
126104
*/
127-
_getAllContractArtefactsfromOutput (compilerOutput, contractName) {
105+
_getAllContractArtefactsfromOutput(compilerOutput, contractName) {
128106
const contractArtefacts = {}
129107
for (const filename in compilerOutput) {
130108
if (Object.keys(compilerOutput[filename]).includes(contractName)) contractArtefacts[filename + ':' + contractName] = compilerOutput[filename][contractName]
@@ -139,12 +117,12 @@ export class CompilerArtefacts extends Plugin {
139117
* @param contractArtefacts populated resultant artefacts object, with fully qualified name (e.g: contracts/1_Storage.sol:Storage) as key
140118
* Once method execution completes, contractArtefacts object will hold all possible artefacts for contract
141119
*/
142-
async _populateAllContractArtefactsFromFE (path, contractName, contractArtefacts) {
120+
async _populateAllContractArtefactsFromFE(path, contractName, contractArtefacts) {
143121
const dirList = await this.call('fileManager', 'dirList', path)
144122
if (dirList && dirList.length) {
145123
for (const dirPath of dirList) {
146124
// check if directory contains an 'artifacts' folder and a 'build-info' folder inside 'artifacts'
147-
if (dirPath === path + '/artifacts' && await this.call('fileManager', 'exists', dirPath + '/build-info')) {
125+
if (dirPath === path + '/artifacts' && (await this.call('fileManager', 'exists', dirPath + '/build-info'))) {
148126
const buildFileList = await this.call('fileManager', 'fileList', dirPath + '/build-info')
149127
// process each build-info file to populate the artefacts for contractName
150128
for (const buildFile of buildFileList) {
@@ -155,7 +133,7 @@ export class CompilerArtefacts extends Plugin {
155133
// populate the resultant object with artefacts
156134
Object.assign(contractArtefacts, artefacts)
157135
}
158-
} else await this._populateAllContractArtefactsFromFE (dirPath, contractName, contractArtefacts)
136+
} else await this._populateAllContractArtefactsFromFE(dirPath, contractName, contractArtefacts)
159137
}
160138
} else return
161139
}
@@ -165,31 +143,30 @@ export class CompilerArtefacts extends Plugin {
165143
* @param name contract name or fully qualified name i.e. <filename>:<contractname> e.g: contracts/1_Storage.sol:Storage
166144
* @returns artefacts for the contract
167145
*/
168-
async getArtefactsByContractName (name) {
146+
async getArtefactsByContractName(name) {
169147
const contractsDataByFilename = this.getAllContractDatas()
170148
// check if name is a fully qualified name
171149
if (name.includes(':')) {
172150
const fullyQualifiedName = name
173151
const nameArr = fullyQualifiedName.split(':')
174152
const filename = nameArr[0]
175153
const contract = nameArr[1]
176-
if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract])
177-
return contractsDataByFilename[filename][contract]
154+
if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract]) return contractsDataByFilename[filename][contract]
178155
else {
179156
const allContractsData = {}
180-
await this._populateAllContractArtefactsFromFE ('contracts', contract, allContractsData)
181-
if (allContractsData[fullyQualifiedName]) return { fullyQualifiedName, artefact: allContractsData[fullyQualifiedName] }
157+
await this._populateAllContractArtefactsFromFE('contracts', contract, allContractsData)
158+
if (allContractsData[fullyQualifiedName]) return {fullyQualifiedName, artefact: allContractsData[fullyQualifiedName]}
182159
else throw new Error(`Could not find artifacts for ${fullyQualifiedName}. Compile contract to generate artifacts.`)
183160
}
184161
} else {
185162
const contractName = name
186163
const contractArtefacts = this._getAllContractArtefactsfromOutput(contractsDataByFilename, contractName)
187164
let keys = Object.keys(contractArtefacts)
188165
if (!keys.length) {
189-
await this._populateAllContractArtefactsFromFE ('contracts', contractName, contractArtefacts)
166+
await this._populateAllContractArtefactsFromFE('contracts', contractName, contractArtefacts)
190167
keys = Object.keys(contractArtefacts)
191168
}
192-
if (keys.length === 1) return { fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]] }
169+
if (keys.length === 1) return {fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]]}
193170
else if (keys.length > 1) {
194171
throw new Error(`There are multiple artifacts for contract "${contractName}", please use a fully qualified name.\n
195172
Please replace ${contractName} for one of these options wherever you are trying to read its artifact: \n
@@ -199,7 +176,7 @@ export class CompilerArtefacts extends Plugin {
199176
}
200177
}
201178

202-
async getCompilerAbstract (file) {
179+
async getCompilerAbstract(file) {
203180
if (!file) return null
204181
if (this.compilersArtefactsPerFile[file]) return this.compilersArtefactsPerFile[file]
205182
const path = await this.call('fileManager', 'getPathFromUrl', file)
@@ -215,30 +192,30 @@ export class CompilerArtefacts extends Plugin {
215192
return artefact
216193
}
217194

218-
addResolvedContract (address: string, compilerData: CompilerAbstract) {
195+
addResolvedContract(address: string, compilerData: CompilerAbstract) {
219196
this.compilersArtefacts[address] = compilerData
220197
}
221198

222-
isResolved (address) {
199+
isResolved(address) {
223200
return this.compilersArtefacts[address] !== undefined
224201
}
225202

226-
get (key) {
203+
get(key) {
227204
return this.compilersArtefacts[key]
228205
}
229206

230-
async getContractDataFromAddress (address) {
207+
async getContractDataFromAddress(address) {
231208
const code = await this.call('blockchain', 'getCode', address)
232209
return this.getContractDataFromByteCode(code)
233210
}
234211

235-
async getContractDataFromByteCode (code) {
212+
async getContractDataFromByteCode(code) {
236213
let found
237214
this.filterAllContractDatas((file, contractsData) => {
238215
for (const name of Object.keys(contractsData)) {
239216
const contract = contractsData[name]
240217
if (util.compareByteCode(code, '0x' + contract.evm.deployedBytecode.object)) {
241-
found = { name, contract, file }
218+
found = {name, contract, file}
242219
return true
243220
}
244221
}

0 commit comments

Comments
 (0)