Skip to content

Commit d071130

Browse files
jrainvilleiurimatias
authored andcommitted
fix(contracts): fix linking libraries with long paths using output
1 parent 2dea50a commit d071130

File tree

3 files changed

+47
-30
lines changed

3 files changed

+47
-30
lines changed

src/lib/modules/contracts_manager/index.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ class ContractsManager {
332332
contract.code = compiledContract.code;
333333
contract.runtimeBytecode = compiledContract.runtimeBytecode;
334334
contract.realRuntimeBytecode = (compiledContract.realRuntimeBytecode || compiledContract.runtimeBytecode);
335+
contract.linkReferences = compiledContract.linkReferences;
335336
contract.swarmHash = compiledContract.swarmHash;
336337
contract.gasEstimates = compiledContract.gasEstimates;
337338
contract.functionHashes = compiledContract.functionHashes;
@@ -467,12 +468,13 @@ class ContractsManager {
467468
self.contractDependencies[className] = self.contractDependencies[className].concat(contract.deps);
468469
}
469470

470-
// look in code for dependencies
471-
if (contract.code) {
472-
let libMatches = (contract.code.match(/:(.*?)(?=_)/g) || []);
473-
for (let match of libMatches) {
474-
self.contractDependencies[className].push(match.substr(1));
475-
}
471+
// look in linkReferences for dependencies
472+
if (contract.linkReferences) {
473+
Object.values(contract.linkReferences).forEach(fileReference => {
474+
Object.keys(fileReference).forEach(libName => {
475+
self.contractDependencies[className].push(libName);
476+
});
477+
});
476478
}
477479

478480
// look in arguments for dependencies

src/lib/modules/deployment/contract_deployer.js

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -209,32 +209,46 @@ class ContractDeployer {
209209

210210
async.waterfall([
211211
function doLinking(next) {
212+
213+
if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) {
214+
return next();
215+
}
212216
let contractCode = contract.code;
213-
self.events.request('contracts:list', (_err, contracts) => {
214-
for (let contractObj of contracts) {
215-
let filename = contractObj.filename;
216-
let deployedAddress = contractObj.deployedAddress;
217-
if (deployedAddress) {
218-
deployedAddress = deployedAddress.substr(2);
219-
}
220-
let linkReference = '__' + filename + ":" + contractObj.className;
221-
if (contractCode.indexOf(linkReference.substr(0, 38)) < 0) { // substr to simulate the cut that solc does
222-
continue;
223-
}
224-
if (linkReference.length > 40) {
225-
return next(new Error(__("{{linkReference}} is too long, try reducing the path of the contract ({{filename}}) and/or its name {{contractName}}", {linkReference: linkReference, filename: filename, contractName: contractObj.className})));
226-
}
227-
let toReplace = linkReference + "_".repeat(40 - linkReference.length);
228-
if (deployedAddress === undefined) {
229-
let libraryName = contractObj.className;
230-
return next(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {contractName: contract.className, libraryName: libraryName})));
231-
}
232-
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
233-
}
234-
// saving code changes back to the contract object
217+
let offset = 0;
218+
219+
async.eachLimit(contract.linkReferences, 1, (fileReference, eachCb1) => {
220+
async.eachOfLimit(fileReference, 1, (references, libName, eachCb2) => {
221+
self.events.request("contracts:contract", libName, (libContract) => {
222+
async.eachLimit(references, 1, (reference, eachCb3) => {
223+
if (!libContract) {
224+
return eachCb3(new Error(__('{{contractName}} has a link to the library {{libraryName}}, but it was not found. Is it in your contract folder?'), {
225+
contractName: contract.className,
226+
libraryName: libName
227+
}));
228+
}
229+
230+
let libAddress = libContract.deployedAddress;
231+
if (!libAddress) {
232+
return eachCb3(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {
233+
contractName: contract.className,
234+
libraryName: libName
235+
})));
236+
}
237+
238+
libAddress = libAddress.substr(2).toLowerCase();
239+
240+
// Multiplying by two because the original pos and length are in bytes, but we have an hex string
241+
contractCode = contractCode.substring(0, (reference.start * 2) + offset) + libAddress + contractCode.substring((reference.start * 2) + offset + (reference.length * 2));
242+
// Calculating an offset in case the length is at some point different than the address length
243+
offset += libAddress.length - (reference.length * 2);
244+
245+
eachCb3();
246+
}, eachCb2);
247+
});
248+
}, eachCb1);
249+
}, (err) => {
235250
contract.code = contractCode;
236-
self.events.request('contracts:setBytecode', contract.className, contractCode);
237-
next();
251+
next(err);
238252
});
239253
},
240254
function applyBeforeDeploy(next) {

src/lib/modules/solidity/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class Solidity {
136136

137137
compiled_object[className] = {};
138138
compiled_object[className].code = contract.evm.bytecode.object;
139+
compiled_object[className].linkReferences = contract.evm.bytecode.linkReferences;
139140
compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object;
140141
compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
141142
compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);

0 commit comments

Comments
 (0)