mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-11 14:24:24 +00:00
Progress
This commit is contained in:
parent
253d3dd57c
commit
8e396a17d8
@ -1,22 +1,37 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ContractSource = require('./contract_source');
|
||||
|
||||
class ContractSources {
|
||||
constructor(files) {
|
||||
if(!Array.isArray(files))
|
||||
files = [files];
|
||||
|
||||
this.files = {};
|
||||
|
||||
switch(Object.prototype.toString.call(files)) {
|
||||
case '[object Object]':
|
||||
Object.keys(files).forEach((file) => {
|
||||
var basename = path.basename(file);
|
||||
this.files[basename] = new ContractSource(basename, files[file]);
|
||||
});
|
||||
|
||||
break;
|
||||
case '[object String]':
|
||||
// No 'break' statement here on purpose, as it shares
|
||||
// the logic below.
|
||||
files = [files];
|
||||
|
||||
case '[object Array]':
|
||||
files.forEach((file) => {
|
||||
var basename = path.basename(file);
|
||||
try {
|
||||
var content = fs.readFileSync(file).toString()
|
||||
this.files[file] = new ContractSource(file, content);
|
||||
var content = fs.readFileSync(file).toString();
|
||||
this.files[basename] = new ContractSource(basename, content);
|
||||
} catch(e) {
|
||||
throw new Error(`Error loading ${file}: ${e.code}`)
|
||||
throw new Error(`Error loading ${file}: ${e.code}`);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
toSolcInputs() {
|
||||
@ -31,8 +46,14 @@ class ContractSources {
|
||||
|
||||
parseSolcOutput(output) {
|
||||
for(var file in output.contracts) {
|
||||
var contractSource = this.files[file];
|
||||
contractSource.parseSolcOutput(output.sources[file], output.contracts[file])
|
||||
var basename = path.basename(file);
|
||||
var contractSource = this.files[basename];
|
||||
if(!contractSource){
|
||||
continue; // TODO CHECK THIS LOGIC
|
||||
throw new Error(`Can't attribute output to ${file}: file has not been read in.`);
|
||||
}
|
||||
|
||||
contractSource.parseSolcOutput(output.sources[file], output.contracts[file]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +65,33 @@ class ContractSources {
|
||||
coverageReport[file] = contractSource.generateCodeCoverage(trace);
|
||||
}
|
||||
|
||||
return coverageReport;
|
||||
if(!this.coverageReport) {
|
||||
this.coverageReport = coverageReport;
|
||||
return this.coverageReport;
|
||||
}
|
||||
|
||||
// We already have a previous coverage report, so we're merging results here.
|
||||
Object.keys(coverageReport).forEach((file) => {
|
||||
if(!this.coverageReport[file]) {
|
||||
this.coverageReport[file] = coverageReport[file];
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment counters for statements, functions and lines
|
||||
['s', 'f', 'l'].forEach((countType) => {
|
||||
Object.keys(coverageReport[file][countType]).forEach((id) => {
|
||||
this.coverageReport[file][countType][id] += coverageReport[file][countType][id];
|
||||
});
|
||||
});
|
||||
|
||||
// Branch counts are tracked in a different manner so we'll do these now
|
||||
Object.keys(coverageReport[file].b).forEach((id) => {
|
||||
this.coverageReport[file].b[id][0] += coverageReport[file].b[id][0];
|
||||
this.coverageReport[file].b[id][1] += coverageReport[file].b[id][1];
|
||||
});
|
||||
});
|
||||
|
||||
return this.coverageReport;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,36 @@
|
||||
const ContractSources = require('./contract_sources');
|
||||
|
||||
class CodeCoverage {
|
||||
constructor(embark, _options) {
|
||||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
|
||||
embark.events.on('contracts:compile:solc', this.compileSolc.bind(this));
|
||||
embark.events.on('contracts:compiled:solc', this.compiledSolc.bind(this));
|
||||
embark.events.on('contracts:run:solc', this.runSolc.bind(this));
|
||||
embark.registerActionForEvent('contracts:deploy:afterAll', this.deployed.bind(this));
|
||||
|
||||
embark.events.on('block:header', this.runSolc.bind(this));
|
||||
}
|
||||
|
||||
compileSolc(input) {
|
||||
var sources = {};
|
||||
|
||||
Object.keys(input.sources).forEach((path) => {
|
||||
sources[path] = input.sources[path].content;
|
||||
});
|
||||
|
||||
this.contractSources = new ContractSources(sources);
|
||||
}
|
||||
|
||||
compiledSolc(output) {
|
||||
this.contractSources.parseSolcOutput(output);
|
||||
}
|
||||
|
||||
runSolc(receipt) {
|
||||
console.log('runSolc');
|
||||
console.dir(receipt);
|
||||
//this.contractSources.generateCodeCoverage(trace);
|
||||
}
|
||||
|
||||
deployed(cb) {
|
||||
|
30
lib/modules/coverage/source_map.js
Normal file
30
lib/modules/coverage/source_map.js
Normal file
@ -0,0 +1,30 @@
|
||||
class SourceMap {
|
||||
constructor(sourceMapStringOrOffset, length, id) {
|
||||
if(typeof sourceMapStringOrOffset == 'string') {
|
||||
var [offset, length, id, ..._rest] = sourceMapStringOrOffset.split(":");
|
||||
|
||||
this.offset = parseInt(offset, 10);
|
||||
this.length = parseInt(length, 10);
|
||||
|
||||
if(id) this.id = parseInt(id, 10);
|
||||
} else {
|
||||
this.offset = sourceMapStringOrOffset;
|
||||
this.length = length;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
subtract(sourceMap) {
|
||||
var length = sourceMap.offset - this.offset;
|
||||
return new SourceMap(this.offset, length);
|
||||
}
|
||||
|
||||
toString() {
|
||||
var parts = [this.offset, this.length];
|
||||
if(this.id) parts.push(this.id);
|
||||
|
||||
return parts.join(':');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SourceMap;
|
@ -200,6 +200,7 @@ class ContractDeployer {
|
||||
}
|
||||
// saving code changes back to the contract object
|
||||
contract.code = contractCode;
|
||||
self.events.request('contracts:setBytecode', contract.className, contractCode);
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
@ -37,7 +37,7 @@ class Solidity {
|
||||
self.logger.error(__('Error while loading the content of ') + filename);
|
||||
return fileCb();
|
||||
}
|
||||
input[filename] = {content: fileContent.replace(/\r\n/g, '\n')};
|
||||
input[filename] = {content: fileContent.replace(/\r\n/g, '\n'), path: file.path};
|
||||
fileCb();
|
||||
});
|
||||
},
|
||||
@ -70,16 +70,34 @@ class Solidity {
|
||||
},
|
||||
outputSelection: {
|
||||
'*': {
|
||||
'*': ['abi', 'metadata', 'userdoc', 'devdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates']
|
||||
'': [
|
||||
'ast',
|
||||
'legacyAST'
|
||||
],
|
||||
'*': [
|
||||
'abi',
|
||||
'devdoc',
|
||||
'evm.bytecode',
|
||||
'evm.deployedBytecode',
|
||||
'evm.gasEstimates',
|
||||
'evm.legacyAssembly',
|
||||
'evm.methodIdentifiers',
|
||||
'metadata',
|
||||
'userdoc'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.solcW.compile(jsonObj, function (err, output) {
|
||||
self.events.emit('contracts:compile:solc', jsonObj);
|
||||
|
||||
if(err){
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
output.errors = []; // TODO REMOVE THIS
|
||||
if (output.errors) {
|
||||
for (let i=0; i<output.errors.length; i++) {
|
||||
if (output.errors[i].type === 'Warning') {
|
||||
@ -90,6 +108,10 @@ class Solidity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//self.plugins.emitAndRunActionsForEvent('contracts:compiled:solc', output);
|
||||
self.events.emit('contracts:compiled:solc', output);
|
||||
|
||||
callback(null, output);
|
||||
});
|
||||
},
|
||||
|
47
package-lock.json
generated
47
package-lock.json
generated
@ -1490,6 +1490,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"assertion-error": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||
"dev": true
|
||||
},
|
||||
"assign-symbols": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
|
||||
@ -2849,6 +2855,20 @@
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz",
|
||||
"integrity": "sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw=="
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
|
||||
"integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assertion-error": "^1.0.1",
|
||||
"check-error": "^1.0.1",
|
||||
"deep-eql": "^3.0.0",
|
||||
"get-func-name": "^2.0.0",
|
||||
"pathval": "^1.0.0",
|
||||
"type-detect": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
@ -2866,6 +2886,12 @@
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
|
||||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
|
||||
},
|
||||
"check-error": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
|
||||
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
@ -3625,6 +3651,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"deep-eql": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
||||
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-detect": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||
@ -5095,6 +5130,12 @@
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
|
||||
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="
|
||||
},
|
||||
"get-func-name": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
|
||||
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
|
||||
"dev": true
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
@ -8835,6 +8876,12 @@
|
||||
"pify": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"pathval": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
|
||||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||
"dev": true
|
||||
},
|
||||
"pbkdf2": {
|
||||
"version": "3.0.16",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz",
|
||||
|
@ -102,6 +102,7 @@
|
||||
"devDependencies": {
|
||||
"eslint": "4.13.1",
|
||||
"mocha-sinon": "^1.1.4",
|
||||
"sinon": "^4.5.0"
|
||||
"sinon": "^4.5.0",
|
||||
"chai": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
237
test/coverage.js
Normal file
237
test/coverage.js
Normal file
@ -0,0 +1,237 @@
|
||||
const {assert, expect} = require('chai');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sinon = require('sinon');
|
||||
|
||||
const ContractSources = require('../lib/modules/coverage/contract_sources');
|
||||
const ContractSource = require('../lib/modules/coverage/contract_source');
|
||||
const SourceMap = require('../lib/modules/coverage/source_map');
|
||||
|
||||
function fixturePath(fixture) {
|
||||
return path.join(__dirname, 'fixtures', fixture);
|
||||
}
|
||||
|
||||
function loadFixture(fixture) {
|
||||
return fs.readFileSync(fixturePath(fixture)).toString();
|
||||
}
|
||||
|
||||
function dumpToFile(obj, path) {
|
||||
return fs.writeFileSync(path, JSON.stringify(obj));
|
||||
}
|
||||
|
||||
describe('ContractSources', () => {
|
||||
describe('constructor', () => {
|
||||
it('should read files and create instances of ContractSource', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources([contractPath]);
|
||||
assert.instanceOf(cs.files['cont.sol'], ContractSource);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should work when a single path is passed', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources(contractPath);
|
||||
assert.instanceOf(cs.files['cont.sol'], ContractSource);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should throw an error when the file does not exist', (done) => {
|
||||
assert.throws(() => {
|
||||
new ContractSources(['fixtures/404.sol'])
|
||||
}, 'Error loading fixtures/404.sol: ENOENT');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toSolcInputs', () => {
|
||||
it('should build the hash in the format that solc likes', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources([contractPath]);
|
||||
assert.deepEqual({
|
||||
'cont.sol': {content: cs.files['cont.sol'].body}
|
||||
}, cs.toSolcInputs());
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#parseSolcOutput', () => {
|
||||
it('should send the output to each of the ContractSource instances', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources([contractPath]);
|
||||
|
||||
var parseSolcOutputSpy = sinon.spy(cs.files['cont.sol'], 'parseSolcOutput');
|
||||
const solcOutput = JSON.parse(loadFixture('solc-output.json'));
|
||||
cs.parseSolcOutput(solcOutput);
|
||||
|
||||
assert(parseSolcOutputSpy.calledOnce);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ContractSource', () => {
|
||||
const contractSource = `
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract x {
|
||||
int number;
|
||||
string name;
|
||||
|
||||
constructor(string _name)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
}
|
||||
|
||||
function g(int _number)
|
||||
public
|
||||
returns (int _multiplication)
|
||||
{
|
||||
number = _number;
|
||||
return _number * 5;
|
||||
}
|
||||
|
||||
function f(int _foo, int _bar)
|
||||
public
|
||||
pure
|
||||
returns (int _addition)
|
||||
{
|
||||
return _foo + _bar;
|
||||
}
|
||||
|
||||
function h(int _bar)
|
||||
public
|
||||
pure
|
||||
returns (bool _great)
|
||||
{
|
||||
if(_bar > 25) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
`.trim();
|
||||
|
||||
const cs = new ContractSource('contract.sol', contractSource);
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should set line offsets and line lengths correctly', (done) => {
|
||||
// +1 here accounts for a newline
|
||||
assert.equal("pragma solidity ^0.4.24;".length + 1, cs.lineOffsets[1]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#sourceMapToLocations', () => {
|
||||
it('should return objects that indicate start and end location and columns', (done) => {
|
||||
// constructor function
|
||||
var loc = cs.sourceMapToLocations('71:60:0');
|
||||
assert.deepEqual({line: 7, column: 2}, loc.start);
|
||||
assert.deepEqual({line: 11, column: 3}, loc.end);
|
||||
|
||||
// f function
|
||||
loc = cs.sourceMapToLocations('257:104:0');
|
||||
assert.deepEqual({line: 21, column: 2}, loc.start);
|
||||
assert.deepEqual({line: 27, column: 3}, loc.end);
|
||||
|
||||
// g function
|
||||
loc = cs.sourceMapToLocations('135:118:0');
|
||||
assert.deepEqual({line: 13, column: 2}, loc.start);
|
||||
assert.deepEqual({line: 19, column: 3}, loc.end);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#parseSolcOutput', () => {
|
||||
it('should parse the bytecode output correctly', (done) => {
|
||||
var solcOutput = JSON.parse(loadFixture('solc-output.json'));
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources(contractPath);
|
||||
cs.parseSolcOutput(solcOutput);
|
||||
|
||||
var contractSource = cs.files['cont.sol'];
|
||||
|
||||
assert.isNotEmpty(contractSource.contractBytecode);
|
||||
assert.isNotEmpty(contractSource.contractBytecode['x']);
|
||||
|
||||
var bytecode = contractSource.contractBytecode['x'];
|
||||
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: '26:487:0:-', seen: false}, bytecode[0]);
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: '', seen: false}, bytecode[2]);
|
||||
assert.deepEqual({instruction: 'MSTORE', sourceMap: '', seen: false}, bytecode[4]);
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: '', seen: false}, bytecode[5]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#generateCodeCoverage', () => {
|
||||
it('should return an error when solc output was not parsed', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources(contractPath);
|
||||
var contractSource = cs.files['cont.sol'];
|
||||
var trace = JSON.parse(loadFixture('geth-debugtrace-output-g.json'));
|
||||
|
||||
assert.throws(() => {
|
||||
contractSource.generateCodeCoverage(trace);
|
||||
}, 'Error generating coverage: solc output was not assigned');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return a coverage report when solc output was parsed', (done) => {
|
||||
var solcOutput = JSON.parse(loadFixture('solc-output.json'));
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources(contractPath);
|
||||
cs.parseSolcOutput(solcOutput);
|
||||
|
||||
var trace = JSON.parse(loadFixture('geth-debugtrace-output-h-5.json'));
|
||||
var coverage = cs.generateCodeCoverage(trace);
|
||||
dumpToFile(coverage, '/tmp/coverage.json');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should merge coverages as we add more traces', (done) => {
|
||||
const contractPath = fixturePath('cont.sol');
|
||||
var cs = new ContractSources(contractPath);
|
||||
|
||||
const solcOutput = JSON.parse(loadFixture('solc-output.json'));
|
||||
cs.parseSolcOutput(solcOutput);
|
||||
|
||||
var trace = JSON.parse(loadFixture('geth-debugtrace-output-h-5.json'));
|
||||
cs.generateCodeCoverage(trace);
|
||||
|
||||
trace = JSON.parse(loadFixture('geth-debugtrace-output-h-50.json'));
|
||||
var coverage = cs.generateCodeCoverage(trace)['cont.sol'];
|
||||
|
||||
// In the fixture, the branch has an ID of 61, and the function has the
|
||||
// ID of 63
|
||||
assert.deepEqual([1,1], coverage.b['61']);
|
||||
assert.equal(2, coverage.f['63']);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SourceMap', () => {
|
||||
describe('#subtract', () => {
|
||||
it('should return the correct values', (done) => {
|
||||
var sm1 = new SourceMap('365:146:0');
|
||||
var sm2 = new SourceMap('428:83:0');
|
||||
|
||||
var result = sm1.subtract(sm2);
|
||||
|
||||
assert.equal(365, result.offset);
|
||||
assert.equal(63, result.length);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
40
test/fixtures/cont.sol
vendored
Normal file
40
test/fixtures/cont.sol
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract x {
|
||||
int number;
|
||||
string name;
|
||||
|
||||
constructor(string _name)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
}
|
||||
|
||||
function g(int _number)
|
||||
public
|
||||
returns (int _multiplication)
|
||||
{
|
||||
number = _number;
|
||||
return _number * 5;
|
||||
}
|
||||
|
||||
function f(int _foo, int _bar)
|
||||
public
|
||||
pure
|
||||
returns (int _addition)
|
||||
{
|
||||
return _foo + _bar;
|
||||
}
|
||||
|
||||
function h(int _bar)
|
||||
public
|
||||
pure
|
||||
returns (bool _great)
|
||||
{
|
||||
if(_bar > 25) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
1234
test/fixtures/geth-debugtrace-output-g.json
vendored
Normal file
1234
test/fixtures/geth-debugtrace-output-g.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1283
test/fixtures/geth-debugtrace-output-h-5.json
vendored
Normal file
1283
test/fixtures/geth-debugtrace-output-h-5.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1303
test/fixtures/geth-debugtrace-output-h-50.json
vendored
Normal file
1303
test/fixtures/geth-debugtrace-output-h-50.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3585
test/fixtures/solc-output.json
vendored
Normal file
3585
test/fixtures/solc-output.json
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user