|
|
|
const web3Utils = require("web3-utils");
|
|
|
|
|
|
|
|
class Injector {
|
|
|
|
constructor(){
|
|
|
|
this.hashCounter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_split(contract, injectionPoint){
|
|
|
|
return {
|
|
|
|
start: contract.instrumented.slice(0, injectionPoint),
|
|
|
|
end: contract.instrumented.slice(injectionPoint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_getInjectable(id, hash, type){
|
|
|
|
return `${this._getMethodIdentifier(id)}(${hash}); /* ${type} */ \n`;
|
|
|
|
}
|
|
|
|
|
|
|
|
_getHash(id) {
|
|
|
|
this.hashCounter++;
|
|
|
|
return web3Utils.keccak256(`${id}:${this.hashCounter}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
_getMethodIdentifier(id){
|
|
|
|
return `c_${web3Utils.keccak256(id).slice(0,10)}`
|
|
|
|
}
|
|
|
|
|
|
|
|
_getInjectionComponents(contract, injectionPoint, id, type){
|
|
|
|
const { start, end } = this._split(contract, injectionPoint);
|
|
|
|
const hash = this._getHash(id)
|
|
|
|
const injectable = this._getInjectable(id, hash, type);
|
|
|
|
|
|
|
|
return {
|
|
|
|
start: start,
|
|
|
|
end: end,
|
|
|
|
hash: hash,
|
|
|
|
injectable: injectable
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates an instrumentation fn definition for contract scoped methods.
|
|
|
|
* Declared once per contract.
|
|
|
|
* @param {String} id
|
|
|
|
* @return {String}
|
|
|
|
*/
|
|
|
|
_getHashMethodDefinition(id, contract){
|
|
|
|
const hash = web3Utils.keccak256(id).slice(0,10);
|
|
|
|
const method = this._getMethodIdentifier(id);
|
|
|
|
return `\nfunction ${method}(bytes32 c__${hash}) public pure {}\n`;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates an instrumentation fn definition for file scoped methods.
|
|
|
|
* Declared once per file. (Has no visibility modifier)
|
|
|
|
* @param {String} id
|
|
|
|
* @return {String}
|
|
|
|
*/
|
|
|
|
_getFileScopedHashMethodDefinition(id, contract){
|
|
|
|
const hash = web3Utils.keccak256(id).slice(0,10);
|
|
|
|
const method = this._getMethodIdentifier(id);
|
|
|
|
return `\nfunction ${method}(bytes32 c__${hash}) pure {}\n`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectLine(contract, fileName, injectionPoint, injection, instrumentation){
|
|
|
|
const type = 'line';
|
|
|
|
const { start, end } = this._split(contract, injectionPoint);
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const newLines = start.match(/\n/g);
|
|
|
|
const linecount = ( newLines || []).length + 1;
|
|
|
|
contract.runnableLines.push(linecount);
|
|
|
|
|
|
|
|
const hash = this._getHash(id)
|
|
|
|
const injectable = this._getInjectable(id, hash, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: linecount,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectStatement(contract, fileName, injectionPoint, injection, instrumentation) {
|
|
|
|
const type = 'statement';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.statementId,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
};
|
|
|
|
|
|
|
|
injectFunction(contract, fileName, injectionPoint, injection, instrumentation){
|
|
|
|
const type = 'function';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.fnId,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectBranch(contract, fileName, injectionPoint, injection, instrumentation){
|
|
|
|
const type = 'branch';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.branchId,
|
|
|
|
locationIdx: injection.locationIdx,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectEmptyBranch(contract, fileName, injectionPoint, injection, instrumentation) {
|
|
|
|
const type = 'branch';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.branchId,
|
|
|
|
locationIdx: injection.locationIdx,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}else { ${injectable}}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectRequirePre(contract, fileName, injectionPoint, injection, instrumentation) {
|
|
|
|
const type = 'requirePre';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.branchId,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectRequirePost(contract, fileName, injectionPoint, injection, instrumentation) {
|
|
|
|
const type = 'requirePost';
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
const {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
hash,
|
|
|
|
injectable
|
|
|
|
} = this._getInjectionComponents(contract, injectionPoint, id, type);
|
|
|
|
|
|
|
|
instrumentation[hash] = {
|
|
|
|
id: injection.branchId,
|
|
|
|
type: type,
|
|
|
|
contractPath: fileName,
|
|
|
|
hits: 0
|
|
|
|
}
|
|
|
|
|
|
|
|
contract.instrumented = `${start}${injectable}${end}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
injectHashMethod(contract, fileName, injectionPoint, injection, instrumentation){
|
|
|
|
const start = contract.instrumented.slice(0, injectionPoint);
|
|
|
|
const end = contract.instrumented.slice(injectionPoint);
|
|
|
|
const id = `${fileName}:${injection.contractName}`;
|
|
|
|
|
|
|
|
contract.instrumented = (injection.isFileScoped)
|
|
|
|
? `${start}${this._getFileScopedHashMethodDefinition(id)}${end}`
|
|
|
|
: `${start}${this._getHashMethodDefinition(id)}${end}`;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = Injector;
|