Skip to content

Commit

Permalink
fix(contracts): fix linking libraries with long paths using output
Browse files Browse the repository at this point in the history
  • Loading branch information
jrainville authored and iurimatias committed Jan 9, 2019
1 parent 2dea50a commit d071130
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 30 deletions.
14 changes: 8 additions & 6 deletions src/lib/modules/contracts_manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ class ContractsManager {
contract.code = compiledContract.code;
contract.runtimeBytecode = compiledContract.runtimeBytecode;
contract.realRuntimeBytecode = (compiledContract.realRuntimeBytecode || compiledContract.runtimeBytecode);
contract.linkReferences = compiledContract.linkReferences;
contract.swarmHash = compiledContract.swarmHash;
contract.gasEstimates = compiledContract.gasEstimates;
contract.functionHashes = compiledContract.functionHashes;
Expand Down Expand Up @@ -467,12 +468,13 @@ class ContractsManager {
self.contractDependencies[className] = self.contractDependencies[className].concat(contract.deps);
}

// look in code for dependencies
if (contract.code) {
let libMatches = (contract.code.match(/:(.*?)(?=_)/g) || []);
for (let match of libMatches) {
self.contractDependencies[className].push(match.substr(1));
}
// look in linkReferences for dependencies
if (contract.linkReferences) {
Object.values(contract.linkReferences).forEach(fileReference => {
Object.keys(fileReference).forEach(libName => {
self.contractDependencies[className].push(libName);
});
});
}

// look in arguments for dependencies
Expand Down
62 changes: 38 additions & 24 deletions src/lib/modules/deployment/contract_deployer.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,32 +209,46 @@ class ContractDeployer {

async.waterfall([
function doLinking(next) {

if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) {
return next();
}
let contractCode = contract.code;
self.events.request('contracts:list', (_err, contracts) => {
for (let contractObj of contracts) {
let filename = contractObj.filename;
let deployedAddress = contractObj.deployedAddress;
if (deployedAddress) {
deployedAddress = deployedAddress.substr(2);
}
let linkReference = '__' + filename + ":" + contractObj.className;
if (contractCode.indexOf(linkReference.substr(0, 38)) < 0) { // substr to simulate the cut that solc does
continue;
}
if (linkReference.length > 40) {
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})));
}
let toReplace = linkReference + "_".repeat(40 - linkReference.length);
if (deployedAddress === undefined) {
let libraryName = contractObj.className;
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})));
}
contractCode = contractCode.replace(new RegExp(toReplace, "g"), deployedAddress);
}
// saving code changes back to the contract object
let offset = 0;

async.eachLimit(contract.linkReferences, 1, (fileReference, eachCb1) => {
async.eachOfLimit(fileReference, 1, (references, libName, eachCb2) => {
self.events.request("contracts:contract", libName, (libContract) => {
async.eachLimit(references, 1, (reference, eachCb3) => {
if (!libContract) {
return eachCb3(new Error(__('{{contractName}} has a link to the library {{libraryName}}, but it was not found. Is it in your contract folder?'), {
contractName: contract.className,
libraryName: libName
}));
}

let libAddress = libContract.deployedAddress;
if (!libAddress) {
return eachCb3(new Error(__("{{contractName}} needs {{libraryName}} but an address was not found, did you deploy it or configured an address?", {
contractName: contract.className,
libraryName: libName
})));
}

libAddress = libAddress.substr(2).toLowerCase();

// Multiplying by two because the original pos and length are in bytes, but we have an hex string
contractCode = contractCode.substring(0, (reference.start * 2) + offset) + libAddress + contractCode.substring((reference.start * 2) + offset + (reference.length * 2));
// Calculating an offset in case the length is at some point different than the address length
offset += libAddress.length - (reference.length * 2);

eachCb3();
}, eachCb2);
});
}, eachCb1);
}, (err) => {
contract.code = contractCode;
self.events.request('contracts:setBytecode', contract.className, contractCode);
next();
next(err);
});
},
function applyBeforeDeploy(next) {
Expand Down
1 change: 1 addition & 0 deletions src/lib/modules/solidity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class Solidity {

compiled_object[className] = {};
compiled_object[className].code = contract.evm.bytecode.object;
compiled_object[className].linkReferences = contract.evm.bytecode.linkReferences;
compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object;
compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);
Expand Down

0 comments on commit d071130

Please sign in to comment.