mirror of
https://github.com/embarklabs/embark.git
synced 2025-01-10 22:05:55 +00:00
feat: add coverage events
Instead of looking at the transaction, instrument the source to publish coverage event
This commit is contained in:
parent
7574e141fa
commit
8a6d075cd1
@ -111,7 +111,7 @@
|
||||
"follow-redirects": "1.5.7",
|
||||
"fs-extra": "7.0.0",
|
||||
"fuzzy": "0.1.3",
|
||||
"ganache-cli": "6.1.8",
|
||||
"ganache-cli": "6.2.3",
|
||||
"glob": "7.1.3",
|
||||
"globule": "1.2.1",
|
||||
"handlebars": "4.0.12",
|
||||
@ -153,6 +153,7 @@
|
||||
"shelljs": "0.5.3",
|
||||
"simples": "0.8.8",
|
||||
"solc": "0.5.0",
|
||||
"solidity-parser-antlr": "0.3.2",
|
||||
"source-map-support": "0.5.9",
|
||||
"stream-json": "1.1.3",
|
||||
"string-replace-async": "1.2.1",
|
||||
@ -191,6 +192,7 @@
|
||||
"@babel/cli": "7.1.2",
|
||||
"@babel/plugin-proposal-optional-chaining": "7.0.0",
|
||||
"@types/async": "2.0.50",
|
||||
"@types/globule": "1.1.3",
|
||||
"@types/handlebars": "4.0.39",
|
||||
"@types/i18n": "0.8.3",
|
||||
"@types/node": "10.11.7",
|
||||
|
@ -56,7 +56,8 @@
|
||||
"restart": "restart"
|
||||
},
|
||||
"tests": {
|
||||
"gasLimit": 6000000
|
||||
"gasLimit": 6000000,
|
||||
"coverageGasLimit": 4503599627370495
|
||||
},
|
||||
"codeGenerator": {
|
||||
"gasLimit": 6000000
|
||||
|
@ -120,6 +120,10 @@ function ensureFileSync() {
|
||||
return restrictPath(fs.ensureFileSync, fs.ensureFileSync, 1, arguments);
|
||||
}
|
||||
|
||||
function ensureDirSync() {
|
||||
return restrictPath(fs.ensureDirSync, fs.ensureDirSync, 1, arguments);
|
||||
}
|
||||
|
||||
function access() {
|
||||
return restrictPath(fs.access, fs.access, 1, arguments);
|
||||
}
|
||||
@ -195,6 +199,7 @@ module.exports = {
|
||||
embarkPath,
|
||||
existsSync,
|
||||
ensureFileSync,
|
||||
ensureDirSync,
|
||||
mkdirp,
|
||||
mkdirpSync,
|
||||
move,
|
||||
|
@ -105,7 +105,8 @@ class BlockchainConnector {
|
||||
|
||||
if (type === 'vm') {
|
||||
const sim = self._getSimulator();
|
||||
self.provider = sim.provider(self.config.contractsConfig.deployment);
|
||||
const options = Object.assign({}, self.config.contractsConfig.deployment, {gasPrice: "0x01", gasLimit: "0xfffffffffffff"});
|
||||
self.provider = sim.provider(options);
|
||||
|
||||
if (coverage) {
|
||||
// Here we patch the sendAsync method on the provider. The goal behind this is to force pure/constant/view calls to become
|
||||
@ -124,7 +125,7 @@ class BlockchainConnector {
|
||||
return self.provider.realSendAsync(payload, cb);
|
||||
}
|
||||
self.events.request('reporter:toggleGasListener');
|
||||
let newParams = Object.assign({}, payload.params[0], {gasPrice: '0x77359400'});
|
||||
let newParams = Object.assign({}, payload.params[0]);
|
||||
let newPayload = {
|
||||
id: payload.id + 1,
|
||||
method: 'eth_sendTransaction',
|
||||
|
143
src/lib/modules/coverage/contractEnhanced.ts
Normal file
143
src/lib/modules/coverage/contractEnhanced.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import * as path from "path";
|
||||
import parser, { Location } from "solidity-parser-antlr";
|
||||
import { EventLog } from "web3/types";
|
||||
|
||||
import { decrypt } from "./eventId";
|
||||
import { Injector } from "./injector";
|
||||
import { Instrumenter } from "./instrumenter";
|
||||
import { InstrumentWalker } from "./instrumentWalker";
|
||||
import { coverageContractsPath } from "./path";
|
||||
import { Suppressor } from "./suppressor";
|
||||
import { BranchType, Coverage } from "./types";
|
||||
|
||||
const fs = require("../../core/fs");
|
||||
|
||||
enum EventEnum {
|
||||
statement = "__StatementCoverage",
|
||||
branch = "__BranchCoverage",
|
||||
function = "__FunctionCoverage",
|
||||
}
|
||||
|
||||
let id = 0;
|
||||
function nextId() {
|
||||
id++;
|
||||
return id;
|
||||
}
|
||||
|
||||
export class ContractEnhanced {
|
||||
public id: number;
|
||||
public coverage: Coverage;
|
||||
public originalSource: string;
|
||||
public source: string;
|
||||
private ast: parser.ASTNode;
|
||||
private coverageFilepath: string;
|
||||
|
||||
constructor(public filepath: string) {
|
||||
this.id = nextId();
|
||||
this.source = fs.readFileSync(filepath, "utf-8");
|
||||
this.originalSource = this.source;
|
||||
|
||||
this.coverageFilepath = path.join(coverageContractsPath(), this.filepath);
|
||||
|
||||
this.coverage = {
|
||||
b: {},
|
||||
branchMap: {},
|
||||
code: this.originalSource,
|
||||
f: {},
|
||||
fnMap: {},
|
||||
l: {},
|
||||
path: filepath,
|
||||
s: {},
|
||||
statementMap: {},
|
||||
};
|
||||
this.ast = parser.parse(this.source, {loc: true, range: true});
|
||||
}
|
||||
|
||||
public instrument() {
|
||||
new Suppressor(this).process();
|
||||
const instrumenter = new Instrumenter(this);
|
||||
const instrumentWalker = new InstrumentWalker(instrumenter);
|
||||
instrumentWalker.walk(this.ast);
|
||||
|
||||
const injector = new Injector(this);
|
||||
instrumenter.getInjectionPoints().forEach(injector.process.bind(injector));
|
||||
}
|
||||
|
||||
public save() {
|
||||
fs.ensureFileSync(this.coverageFilepath);
|
||||
fs.writeFileSync(this.coverageFilepath, this.source);
|
||||
}
|
||||
|
||||
public updateCoverage(events: EventLog[]) {
|
||||
events.filter(this.filterCoverageEvent).forEach((event) => {
|
||||
const value = parseInt(event.returnValues[0], 10);
|
||||
const {contractId, injectionPointId, locationIdx} = decrypt(value);
|
||||
|
||||
if (contractId !== this.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.event) {
|
||||
case "__StatementCoverage": {
|
||||
this.coverage.s[injectionPointId] += 1;
|
||||
const statement = this.coverage.statementMap[injectionPointId];
|
||||
this.coverage.l[statement.start.line] += 1;
|
||||
break;
|
||||
}
|
||||
case "__FunctionCoverage": {
|
||||
this.coverage.f[injectionPointId] += 1;
|
||||
const fn = this.coverage.fnMap[injectionPointId];
|
||||
this.coverage.l[fn.line] += 1;
|
||||
break;
|
||||
}
|
||||
case "__BranchCoverage": {
|
||||
this.coverage.b[injectionPointId][locationIdx] += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public addStatement(location: Location) {
|
||||
const coverageId = this.getNewCoverageId(this.coverage.statementMap);
|
||||
this.coverage.statementMap[coverageId] = location;
|
||||
this.coverage.s[coverageId] = 0;
|
||||
this.coverage.l[location.start.line] = 0;
|
||||
return coverageId;
|
||||
}
|
||||
|
||||
public addBranch(line: number, type: BranchType, locations: Location[]) {
|
||||
const coverageId = this.getNewCoverageId(this.coverage.branchMap);
|
||||
this.coverage.branchMap[coverageId] = {
|
||||
line,
|
||||
locations,
|
||||
type,
|
||||
};
|
||||
this.coverage.b[coverageId] = locations.map(() => 0);
|
||||
this.coverage.l[line] = 0;
|
||||
return coverageId;
|
||||
}
|
||||
|
||||
public addFunction(location: Location, name: string) {
|
||||
const coverageId = this.getNewCoverageId(this.coverage.fnMap);
|
||||
const line = location.start.line;
|
||||
this.coverage.fnMap[coverageId] = {
|
||||
line,
|
||||
loc: location,
|
||||
name,
|
||||
};
|
||||
this.coverage.f[coverageId] = 0;
|
||||
this.coverage.l[line] = 0;
|
||||
return coverageId;
|
||||
}
|
||||
|
||||
private getNewCoverageId(object: {[key: string]: any}) {
|
||||
const lastId = Object.keys(object).map(Number).sort((a, b) => b - a)[0] || 0;
|
||||
return lastId + 1;
|
||||
}
|
||||
|
||||
private filterCoverageEvent(event: EventLog) {
|
||||
return [EventEnum.function, EventEnum.branch, EventEnum.statement].includes(event.event as EventEnum);
|
||||
}
|
||||
|
||||
}
|
@ -1,380 +0,0 @@
|
||||
const SourceMap = require('./sourceMap');
|
||||
|
||||
class ContractSource {
|
||||
constructor(file, path, body) {
|
||||
this.file = file;
|
||||
this.path = path;
|
||||
this.body = body;
|
||||
|
||||
this.lineLengths = body.split("\n").map(line => line.length);
|
||||
this.lineCount = this.lineLengths.length;
|
||||
|
||||
this.lineOffsets = this.lineLengths.reduce((sum, _elt, i) => {
|
||||
sum[i] = (i === 0) ? 0 : this.lineLengths[i-1] + sum[i-1] + 1;
|
||||
return sum;
|
||||
}, []);
|
||||
|
||||
this.contracts = {};
|
||||
}
|
||||
|
||||
sourceMapToLocations(sourceMap) {
|
||||
const [offset, length, ..._] = sourceMap.split(":").map((val) => {
|
||||
return parseInt(val, 10);
|
||||
});
|
||||
|
||||
const locations = {};
|
||||
|
||||
for(let i = 0; i < this.lineCount; i++) {
|
||||
if(this.lineOffsets[i+1] <= offset) continue;
|
||||
|
||||
locations.start = {line: i, column: offset - this.lineOffsets[i]};
|
||||
break;
|
||||
}
|
||||
|
||||
for(let i = locations.start.line; i < this.lineCount; i++) {
|
||||
if(this.lineOffsets[i+1] <= offset + length) continue;
|
||||
|
||||
locations.end = {line: i, column: ((offset + length) - this.lineOffsets[i])};
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure we return an "end" as a safeguard if the marker ends up to be
|
||||
// or surpass the offset for last character.
|
||||
if(!locations.end) {
|
||||
const lastLine = this.lineCount - 1;
|
||||
locations.end = {line: lastLine, column: this.lineLengths[lastLine]};
|
||||
}
|
||||
|
||||
// Istanbul likes lines to be 1-indexed, so we'll increment here before returning.
|
||||
locations.start.line++;
|
||||
locations.end.line++;
|
||||
return locations;
|
||||
}
|
||||
|
||||
parseSolcOutput(source, contracts) {
|
||||
this.id = source.id;
|
||||
this.ast = source.ast;
|
||||
this.contractBytecode = {};
|
||||
this.contractDeployedBytecode = {};
|
||||
|
||||
for(const contractName in contracts) {
|
||||
this.contractBytecode[contractName] = {};
|
||||
this.contractDeployedBytecode[contractName] = {};
|
||||
|
||||
var contract = contracts[contractName];
|
||||
var opcodes = contract.evm.bytecode.opcodes.trim().split(' ');
|
||||
var deployedOpcodes = contract.evm.deployedBytecode.opcodes.trim().split(' ');
|
||||
var sourceMaps = contract.evm.bytecode.sourceMap.split(';');
|
||||
var deployedSourceMaps = contract.evm.deployedBytecode.sourceMap.split(';');
|
||||
|
||||
this._buildContractBytecode(contractName, this.contractBytecode, opcodes, sourceMaps);
|
||||
this._buildContractBytecode(contractName, this.contractDeployedBytecode, deployedOpcodes, deployedSourceMaps);
|
||||
}
|
||||
}
|
||||
|
||||
isInterface() {
|
||||
return this.contractBytecode !== undefined &&
|
||||
Object.values(this.contractBytecode).every((contractBytecode) => { return (Object.values(contractBytecode).length <= 1); });
|
||||
}
|
||||
|
||||
/*eslint complexity: ["error", 50]*/
|
||||
generateCodeCoverage(trace) {
|
||||
if(!this.ast || !this.contractBytecode) throw new Error('Error generating coverage: solc output was not assigned');
|
||||
|
||||
const coverage = {
|
||||
code: this.body.trim().split("\n"),
|
||||
l: {},
|
||||
path: this.path,
|
||||
s: {},
|
||||
b: {},
|
||||
f: {},
|
||||
fnMap: {},
|
||||
statementMap: {},
|
||||
branchMap: {}
|
||||
};
|
||||
|
||||
let nodesRequiringVisiting = [this.ast];
|
||||
const sourceMapToNodeType = {};
|
||||
|
||||
do {
|
||||
const node = nodesRequiringVisiting.pop();
|
||||
|
||||
if(!node) continue;
|
||||
|
||||
let children = [];
|
||||
let markLocations = [];
|
||||
let location;
|
||||
switch(node.nodeType) {
|
||||
case 'Assignment':
|
||||
case 'EventDefinition':
|
||||
case 'ImportDirective':
|
||||
case 'Literal':
|
||||
case 'PlaceholderStatement':
|
||||
case 'PragmaDirective':
|
||||
case 'StructDefinition':
|
||||
case 'VariableDeclaration':
|
||||
case 'UsingForDirective':
|
||||
case 'EnumDefinition':
|
||||
// We don't need to do anything with these. Just carry on.
|
||||
break;
|
||||
|
||||
case 'IfStatement': {
|
||||
location = this.sourceMapToLocations(node.src);
|
||||
const trueBranchLocation = this.sourceMapToLocations(node.trueBody.src);
|
||||
|
||||
const declarationSourceMap = new SourceMap(node.src).subtract(new SourceMap(node.trueBody.src));
|
||||
const declarationLocation = this.sourceMapToLocations(declarationSourceMap.toString());
|
||||
|
||||
let falseBranchLocation;
|
||||
if(node.falseBody) {
|
||||
falseBranchLocation = this.sourceMapToLocations(node.falseBody.src);
|
||||
} else {
|
||||
falseBranchLocation = trueBranchLocation;
|
||||
}
|
||||
|
||||
coverage.b[node.id] = [0,0];
|
||||
coverage.branchMap[node.id] = {
|
||||
type: 'if',
|
||||
locations: [trueBranchLocation, falseBranchLocation],
|
||||
line: location.start.line
|
||||
};
|
||||
|
||||
markLocations = [declarationLocation];
|
||||
children = [node.condition];
|
||||
|
||||
const trueExpression = (node.trueBody && node.trueBody.statements && node.trueBody.statements[0]) || node.trueBody;
|
||||
if(trueExpression) {
|
||||
children = children.concat(trueExpression);
|
||||
trueExpression._parent = {type: 'b', id: node.id, idx: 0};
|
||||
}
|
||||
|
||||
const falseExpression = (node.falseBody && node.falseBody.statements && node.falseBody.statements[0]) || node.falseBody;
|
||||
if(falseExpression) {
|
||||
children = children.concat(falseExpression);
|
||||
falseExpression._parent = {type: 'b', id: node.id, idx: 1};
|
||||
}
|
||||
|
||||
sourceMapToNodeType[node.src] = [{type: 'b', id: node.id, body: {loc: location}}];
|
||||
break;
|
||||
}
|
||||
|
||||
case 'EmitStatement': {
|
||||
children = [node.eventCall];
|
||||
break;
|
||||
}
|
||||
|
||||
case 'BinaryOperation':
|
||||
case 'ExpressionStatement':
|
||||
case 'FunctionCall':
|
||||
case 'Identifier':
|
||||
case 'Return':
|
||||
case 'UnaryOperation':
|
||||
coverage.s[node.id] = 0;
|
||||
|
||||
location = this.sourceMapToLocations(node.src);
|
||||
coverage.statementMap[node.id] = location;
|
||||
|
||||
if(!sourceMapToNodeType[node.src]) sourceMapToNodeType[node.src] = [];
|
||||
sourceMapToNodeType[node.src].push({
|
||||
type: 's',
|
||||
id: node.id,
|
||||
body: {loc: coverage.statementMap[node.id]},
|
||||
parent: node._parent
|
||||
});
|
||||
|
||||
markLocations = [location];
|
||||
break;
|
||||
|
||||
case 'ContractDefinition':
|
||||
case 'SourceUnit':
|
||||
children = node.nodes;
|
||||
break;
|
||||
|
||||
case 'ModifierDefinition':
|
||||
case 'FunctionDefinition': {
|
||||
// Istanbul only wants the function definition, not the body, so we're
|
||||
// going to do some fun math here.
|
||||
const functionSourceMap = new SourceMap(node.src);
|
||||
const functionParametersSourceMap = new SourceMap(node.parameters.src);
|
||||
|
||||
const functionDefinitionSourceMap = new SourceMap(
|
||||
functionSourceMap.offset,
|
||||
(functionParametersSourceMap.offset + functionParametersSourceMap.length) - functionSourceMap.offset
|
||||
).toString();
|
||||
|
||||
const fnName = node.isConstructor ? "(constructor)" : node.name;
|
||||
location = this.sourceMapToLocations(functionDefinitionSourceMap);
|
||||
|
||||
coverage.f[node.id] = 0;
|
||||
coverage.fnMap[node.id] = {
|
||||
name: fnName,
|
||||
line: location.start.line,
|
||||
loc: location
|
||||
};
|
||||
|
||||
// Record function positions.
|
||||
sourceMapToNodeType[node.src] = [{type: 'f', id: node.id, body: coverage.fnMap[node.id]}];
|
||||
|
||||
if(node.body) children = node.body.statements;
|
||||
markLocations = [location];
|
||||
break;
|
||||
}
|
||||
case 'WhileStatement':
|
||||
case 'ForStatement': {
|
||||
// For statements will be a bit of a special case. We want to count the body
|
||||
// iterations but we only want to count the for loop being hit once. Because
|
||||
// of this, we cover the initialization on the node.
|
||||
const sourceMap = new SourceMap(node.src);
|
||||
const bodySourceMap = new SourceMap(node.body.src);
|
||||
const forLoopDeclaration = sourceMap.subtract(bodySourceMap).toString();
|
||||
|
||||
location = this.sourceMapToLocations(forLoopDeclaration);
|
||||
|
||||
const markExpression = node.initializationExpression || node.loopExpression || node.condition;
|
||||
const expressionLocation = this.sourceMapToLocations(markExpression.src);
|
||||
|
||||
if(!sourceMapToNodeType[markExpression.src]) sourceMapToNodeType[markExpression.src] = [];
|
||||
sourceMapToNodeType[markExpression.src].push({type: 's', id: node.id, body: {loc: location}});
|
||||
markLocations = [expressionLocation];
|
||||
|
||||
coverage.s[node.id] = 0;
|
||||
coverage.statementMap[node.id] = location;
|
||||
|
||||
children = node.body.statements;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'VariableDeclarationStatement': {
|
||||
location = this.sourceMapToLocations(node.src);
|
||||
|
||||
coverage.s[node.id] = 0;
|
||||
coverage.statementMap[node.id] = location;
|
||||
markLocations = [location];
|
||||
|
||||
if(!sourceMapToNodeType[node.src]) sourceMapToNodeType[node.src] = [];
|
||||
sourceMapToNodeType[node.src].push({type: 's', id: node.id, body: {loc: location}, foo: 'bar'});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
nodesRequiringVisiting = nodesRequiringVisiting.concat(children);
|
||||
|
||||
markLocations.forEach((location) => {
|
||||
for(var i = location.start.line; i <= location.end.line; i++) {
|
||||
coverage.l[i] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
} while(nodesRequiringVisiting.length > 0);
|
||||
|
||||
this._generateCodeCoverageForBytecode(trace, coverage, sourceMapToNodeType, this.contractBytecode);
|
||||
this._generateCodeCoverageForBytecode(trace, coverage, sourceMapToNodeType, this.contractDeployedBytecode);
|
||||
|
||||
return coverage;
|
||||
}
|
||||
|
||||
_generateCodeCoverageForBytecode(trace, coverage, sourceMapToNodeType, contractBytecode) {
|
||||
let contractMatches = true;
|
||||
for(const contractName in contractBytecode) {
|
||||
const bytecode = contractBytecode[contractName];
|
||||
|
||||
// Try to match the contract to the bytecode. If it doesn't,
|
||||
// then we bail.
|
||||
|
||||
contractMatches = trace.structLogs.filter((step) => bytecode[step.pc]);
|
||||
|
||||
if(!contractMatches) continue;
|
||||
contractMatches.forEach((step) => {
|
||||
step = bytecode[step.pc];
|
||||
|
||||
if(!step.sourceMap || step.sourceMap === '' || step.sourceMap === SourceMap.empty()) return;
|
||||
|
||||
const sourceMapString = step.sourceMap.toString(this.id);
|
||||
|
||||
const [offsetToFind, lengthToFind, _] = sourceMapString.split(":");
|
||||
const nodes = this._findNodes(offsetToFind, lengthToFind, sourceMapToNodeType);
|
||||
|
||||
if(!nodes) return;
|
||||
|
||||
nodes.forEach((node) => {
|
||||
// Skip duplicate function reports by only reporting when there is a jump.
|
||||
if(node.type === 'f' && step.jump) return;
|
||||
|
||||
if(node.type !== 'b' && node.body && node.body.loc) {
|
||||
for(let line = node.body.loc.start.line; line <= node.body.loc.end.line; line++) {
|
||||
coverage.l[line]++;
|
||||
}
|
||||
}
|
||||
|
||||
if(node.type !== 'b') coverage[node.type][node.id]++;
|
||||
|
||||
if(!node.parent) return;
|
||||
|
||||
switch(node.parent.type) {
|
||||
case 'b':
|
||||
coverage.b[node.parent.id][node.parent.idx]++;
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_findNodes(offsetToFind, _lengthToFind, sourceMapToNodeType) {
|
||||
let nodes;
|
||||
Object.keys(sourceMapToNodeType).some(sourceMap => {
|
||||
const [offset, _length, _] = sourceMap.split(":");
|
||||
if (offsetToFind === offset) {
|
||||
nodes = sourceMapToNodeType[sourceMap];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
_buildContractBytecode(contractName, contractBytecode, opcodes, sourceMaps) {
|
||||
const bytecodeMapping = contractBytecode[contractName];
|
||||
let bytecodeIdx = 0;
|
||||
let pc = 0;
|
||||
let instructions = 0;
|
||||
let previousSourceMap = null;
|
||||
|
||||
do {
|
||||
let sourceMap;
|
||||
const sourceMapArgs = sourceMaps[instructions];
|
||||
if(previousSourceMap === null) {
|
||||
sourceMap = new SourceMap(sourceMapArgs);
|
||||
} else {
|
||||
sourceMap = previousSourceMap.createRelativeTo(sourceMapArgs);
|
||||
}
|
||||
|
||||
const instruction = opcodes[bytecodeIdx];
|
||||
const length = this._instructionLength(instruction);
|
||||
bytecodeMapping[pc] = {
|
||||
instruction: instruction,
|
||||
sourceMap: sourceMap,
|
||||
jump: sourceMap.jump,
|
||||
seen: false
|
||||
};
|
||||
|
||||
pc += length;
|
||||
instructions++;
|
||||
bytecodeIdx += (length > 1) ? 2 : 1;
|
||||
previousSourceMap = sourceMap;
|
||||
} while(bytecodeIdx < opcodes.length);
|
||||
}
|
||||
|
||||
_instructionLength(instruction) {
|
||||
if(instruction.indexOf('PUSH') === -1) return 1;
|
||||
return parseInt(instruction.match(/PUSH(\d+)/m)[1], 10) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ContractSource;
|
@ -1,101 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ContractSource = require('./contractSource');
|
||||
|
||||
class ContractSources {
|
||||
constructor(files) {
|
||||
this.files = {};
|
||||
|
||||
switch(Object.prototype.toString.call(files)) {
|
||||
case '[object Object]':
|
||||
Object.keys(files).forEach((file) => { this.addFile(file, files[file]); });
|
||||
break;
|
||||
|
||||
case '[object String]':
|
||||
// No 'break' statement here on purpose, as it shares
|
||||
// the logic below.
|
||||
files = [files];
|
||||
// falls through
|
||||
|
||||
case '[object Array]':
|
||||
files.forEach((file) => {
|
||||
const content = fs.readFileSync(file).toString();
|
||||
this.addFile(file, content);
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Don't know how to initialize with ${Object.prototype.toString.call(files)}`);
|
||||
}
|
||||
}
|
||||
|
||||
addFile(fullPath, contents) {
|
||||
const basename = path.basename(fullPath);
|
||||
if(this.files[basename]) return;
|
||||
|
||||
this.files[basename] = new ContractSource(basename, fullPath, contents);
|
||||
}
|
||||
|
||||
toSolcInputs() {
|
||||
const inputs = {};
|
||||
|
||||
for(const filename in this.files) {
|
||||
inputs[filename] = {content: this.files[filename].body};
|
||||
}
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
parseSolcOutput(output) {
|
||||
for(const filename in output.contracts) {
|
||||
const contractSource = this.files[path.basename(filename)];
|
||||
if(!contractSource) continue;
|
||||
|
||||
contractSource.parseSolcOutput(output.sources[filename], output.contracts[filename]);
|
||||
}
|
||||
}
|
||||
|
||||
generateCodeCoverage(trace) {
|
||||
const coverageReport = {};
|
||||
|
||||
for(const filename in this.files) {
|
||||
if(this.files[filename].isInterface()) continue;
|
||||
coverageReport[filename] = this.files[filename].generateCodeCoverage(trace);
|
||||
}
|
||||
|
||||
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) => {
|
||||
// FIXME in solc-tests, this is sometimes empty
|
||||
if (!this.coverageReport[file].b[id] || !this.coverageReport[file].b[id].length) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ContractSources;
|
33
src/lib/modules/coverage/eventId.ts
Normal file
33
src/lib/modules/coverage/eventId.ts
Normal file
@ -0,0 +1,33 @@
|
||||
const CONTRACT_ID_FACTOR = 100000000;
|
||||
const INJECTION_POINT_ID_FACTOR = 10000;
|
||||
|
||||
/**
|
||||
* Convert the 3 params as uint32 where the first 2 digits are for contractsId,
|
||||
* the next 3 digit are for injectionPoint id and the rest if for the locationIds
|
||||
*
|
||||
* @export
|
||||
* @param {number} contractId
|
||||
* @param {number} injectionPointId
|
||||
* @param {number} [locationIdx]
|
||||
* @returns a number representing the 3 params as uint32
|
||||
*/
|
||||
export function encrypt(contractId: number, injectionPointId: number, locationIdx?: number) {
|
||||
return contractId * CONTRACT_ID_FACTOR + injectionPointId * INJECTION_POINT_ID_FACTOR + (locationIdx || 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explore the uint32 into contractId, injectionPointId and locationIds where
|
||||
* the first 2 digits are for contractsId,
|
||||
* the next 3 digit are for injectionPoint id and the rest if for the locationIds
|
||||
*
|
||||
* @export
|
||||
* @param {number} value
|
||||
* @returns
|
||||
*/
|
||||
export function decrypt(value: number) {
|
||||
const contractId = Math.floor(value / CONTRACT_ID_FACTOR);
|
||||
const injectionPointId = Math.floor(value / INJECTION_POINT_ID_FACTOR) - contractId * INJECTION_POINT_ID_FACTOR;
|
||||
const locationIdx = value - contractId * CONTRACT_ID_FACTOR - injectionPointId * INJECTION_POINT_ID_FACTOR;
|
||||
|
||||
return {contractId, injectionPointId, locationIdx};
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*global web3*/
|
||||
const fs = require('../../core/fs');
|
||||
const ContractSources = require('./contractSources');
|
||||
|
||||
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.events.on('block:header', this.runSolc.bind(this));
|
||||
|
||||
embark.events.on('tests:finished', this.updateCoverageReport.bind(this));
|
||||
|
||||
embark.events.on('blockchain:ready', () => {
|
||||
embark.events.request('blockchain:get', (web3) => {
|
||||
// Set up the web3 extension
|
||||
web3.extend({
|
||||
property: 'debug',
|
||||
methods: [{name: 'traceTransaction', call: 'debug_traceTransaction', params: 2}]
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
this.seenTransactions = {};
|
||||
this.coverageReport = {};
|
||||
this.contractSources = new ContractSources([]);
|
||||
|
||||
this.dotEmbarkPath = fs.dappPath('.embark');
|
||||
this.coverageReportPath = fs.dappPath('.embark', 'coverage.json');
|
||||
}
|
||||
|
||||
compileSolc(input) {
|
||||
Object.keys(input.sources).forEach((file) => {
|
||||
this.contractSources.addFile(file, input.sources[file].content);
|
||||
});
|
||||
}
|
||||
|
||||
compiledSolc(output) {
|
||||
this.contractSources.parseSolcOutput(output);
|
||||
}
|
||||
|
||||
updateCoverageReport(cb) {
|
||||
fs.mkdirp(this.dotEmbarkPath, () => {
|
||||
fs.writeFile(this.coverageReportPath, JSON.stringify(this.coverageReport), cb);
|
||||
});
|
||||
}
|
||||
|
||||
async runSolc(receipt) {
|
||||
let block = await web3.eth.getBlock(receipt.number);
|
||||
if(block.transactions.length === 0) return;
|
||||
|
||||
let requests = block.transactions.reduce((acc, txHash) => {
|
||||
if(this.seenTransactions[txHash]) return;
|
||||
|
||||
this.seenTransactions[txHash] = true;
|
||||
acc.push(web3.debug.traceTransaction(txHash, {}));
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
let traces = await Promise.all(requests);
|
||||
|
||||
traces.forEach(trace => {
|
||||
this.coverageReport = this.contractSources.generateCodeCoverage(trace);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CodeCoverage;
|
121
src/lib/modules/coverage/index.ts
Normal file
121
src/lib/modules/coverage/index.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import * as globule from "globule";
|
||||
import * as path from "path";
|
||||
import { Contract as Web3Contract } from "web3/types";
|
||||
|
||||
import { Contract } from "../../../typings/contract";
|
||||
import { Embark } from "../../../typings/embark";
|
||||
import { ContractEnhanced } from "./contractEnhanced";
|
||||
import { coverageContractsPath } from "./path";
|
||||
import { Coverage as ICoverage } from "./types";
|
||||
|
||||
const fs = require("../../core/fs");
|
||||
|
||||
export default class Coverage {
|
||||
private contracts: ContractEnhanced[];
|
||||
private deployedContracts: Contract[] = [];
|
||||
private web3Contracts: Web3Contract[] = [];
|
||||
private contractsDir: string[] = [];
|
||||
|
||||
constructor(private embark: Embark, options: any) {
|
||||
fs.ensureDirSync(coverageContractsPath());
|
||||
|
||||
const contractsDirConfig = this.embark.config.embarkConfig.contracts;
|
||||
this.contractsDir = Array.isArray(contractsDirConfig) ? contractsDirConfig : [contractsDirConfig];
|
||||
|
||||
this.contracts = this.getContracts();
|
||||
|
||||
this.instrumentContracts();
|
||||
this.swapContracts();
|
||||
|
||||
this.embark.events.on("tests:ready", this.pushDeployedContracts.bind(this));
|
||||
this.embark.events.on("tests:finished", this.produceCoverageReport.bind(this));
|
||||
this.embark.events.on("tests:manualDeploy", this.registerWeb3Contract.bind(this));
|
||||
}
|
||||
|
||||
private getContracts() {
|
||||
const filepaths = this.contractsDir.reduce((acc: string[], pattern: string) => (
|
||||
acc.concat(globule.find(pattern, { prefixBase: false, srcBase: fs.dappPath() }))
|
||||
), []);
|
||||
|
||||
return filepaths.filter((filepath) => fs.statSync(filepath).isFile())
|
||||
.map((filepath) => new ContractEnhanced(filepath));
|
||||
}
|
||||
|
||||
private instrumentContracts() {
|
||||
this.contracts.forEach((contract) => contract.instrument());
|
||||
}
|
||||
|
||||
private swapContracts() {
|
||||
this.contracts.forEach((contract) => {
|
||||
contract.save();
|
||||
});
|
||||
|
||||
this.embark.config.embarkConfig.contracts = this.contractsDir.reduce((acc: string[], value: string) => (
|
||||
acc.concat(path.join(coverageContractsPath(), value))
|
||||
), []);
|
||||
this.embark.config.contractsFiles = [];
|
||||
this.embark.config.reloadConfig();
|
||||
}
|
||||
|
||||
private async pushDeployedContracts() {
|
||||
const newContracts = await this.getDeployedContracts();
|
||||
this.deployedContracts = this.deployedContracts.concat(newContracts);
|
||||
}
|
||||
|
||||
private async produceCoverageReport(cb: () => void) {
|
||||
const web3Contracts = await this.getWeb3Contracts();
|
||||
await Promise.all(this.collectEvents(web3Contracts));
|
||||
this.writeCoverageReport(cb);
|
||||
}
|
||||
|
||||
private writeCoverageReport(cb: () => void) {
|
||||
fs.ensureDirSync(path.join(fs.dappPath(), ".embark"));
|
||||
const coveragePath = path.join(fs.dappPath(), ".embark", "coverage.json");
|
||||
|
||||
const coverageReport = this.contracts.reduce((acc: {[name: string]: ICoverage}, contract) => {
|
||||
acc[contract.filepath] = contract.coverage;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
fs.writeFile(coveragePath, JSON.stringify(coverageReport, null, 2), cb);
|
||||
}
|
||||
|
||||
private collectEvents(web3Contracts: Web3Contract[]) {
|
||||
return web3Contracts.map(async (web3Contract) => {
|
||||
const events = await web3Contract.getPastEvents("allEvents", {fromBlock: 0});
|
||||
this.contracts.forEach((contract) => contract.updateCoverage(events));
|
||||
});
|
||||
}
|
||||
|
||||
private getWeb3Contract(deployedContract: Contract) {
|
||||
return new Promise<Web3Contract>((resolve) => {
|
||||
const address = deployedContract.deployedAddress;
|
||||
const abi = deployedContract.abiDefinition;
|
||||
this.embark.events.request("blockchain:contract:create", {address, abi}, (web3Contract: Web3Contract) => {
|
||||
resolve(web3Contract);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getDeployedContracts() {
|
||||
return new Promise<Contract[]>((resolve, reject) => {
|
||||
this.embark.events.request("contracts:all", (error: Error, contracts: {[name: string]: Contract}) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
resolve(Object.values(contracts));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async getWeb3Contracts() {
|
||||
const web3Contracts = this.deployedContracts.filter((deployedContract) => deployedContract.deployedAddress)
|
||||
.map((deployedContract) => this.getWeb3Contract(deployedContract));
|
||||
|
||||
return (await Promise.all(web3Contracts)).concat(this.web3Contracts);
|
||||
}
|
||||
|
||||
private registerWeb3Contract(web3Contract: Web3Contract) {
|
||||
this.web3Contracts.push(web3Contract);
|
||||
}
|
||||
}
|
53
src/lib/modules/coverage/injector.ts
Normal file
53
src/lib/modules/coverage/injector.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { ContractEnhanced } from "./contractEnhanced";
|
||||
import { encrypt } from "./eventId";
|
||||
import { InjectionPoint } from "./types";
|
||||
|
||||
export class Injector {
|
||||
|
||||
constructor(private contract: ContractEnhanced) {
|
||||
}
|
||||
|
||||
public process(injectionPoint: InjectionPoint) {
|
||||
switch (injectionPoint.type) {
|
||||
case "statement":
|
||||
return this.statement(injectionPoint);
|
||||
case "function":
|
||||
return this.function(injectionPoint);
|
||||
case "branch":
|
||||
return this.branch(injectionPoint);
|
||||
case "contractDefinition":
|
||||
return this.contractDefinition(injectionPoint);
|
||||
}
|
||||
}
|
||||
|
||||
private statement(injectionPoint: InjectionPoint) {
|
||||
const data = `emit __StatementCoverage(${encrypt(this.contract.id, injectionPoint.id)});`;
|
||||
this.insertAt(injectionPoint.location.start.line - 1, data);
|
||||
}
|
||||
|
||||
private function(injectionPoint: InjectionPoint) {
|
||||
const data = `emit __FunctionCoverage(${encrypt(this.contract.id, injectionPoint.id)});`;
|
||||
this.insertAt(injectionPoint.location.start.line, data);
|
||||
}
|
||||
|
||||
private branch(injectionPoint: InjectionPoint) {
|
||||
const data = `emit __BranchCoverage(${encrypt(this.contract.id, injectionPoint.id, injectionPoint.locationIdx)});`;
|
||||
this.insertAt(injectionPoint.location.start.line, data);
|
||||
}
|
||||
|
||||
private contractDefinition(injectionPoint: InjectionPoint) {
|
||||
const data = [
|
||||
"event __FunctionCoverage(uint32 value);",
|
||||
"event __StatementCoverage(uint32 value);",
|
||||
"event __BranchCoverage(uint32 value);",
|
||||
].join("\n");
|
||||
|
||||
this.insertAt(injectionPoint.location.start.line, data);
|
||||
}
|
||||
|
||||
private insertAt(line: number, data: string) {
|
||||
const lines = this.contract.source.split("\n");
|
||||
lines.splice(line, 0, data);
|
||||
this.contract.source = lines.join("\n");
|
||||
}
|
||||
}
|
63
src/lib/modules/coverage/instrumentWalker.ts
Normal file
63
src/lib/modules/coverage/instrumentWalker.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import parser, {
|
||||
ASTNode,
|
||||
BreakStatement,
|
||||
ContinueStatement,
|
||||
ContractDefinition,
|
||||
EmitStatement,
|
||||
ExpressionStatement,
|
||||
FunctionDefinition,
|
||||
IfStatement,
|
||||
ModifierDefinition,
|
||||
ReturnStatement,
|
||||
ThrowStatement,
|
||||
VariableDeclarationStatement,
|
||||
WhileStatement,
|
||||
} from "solidity-parser-antlr";
|
||||
import { Instrumenter } from "./instrumenter";
|
||||
|
||||
export class InstrumentWalker {
|
||||
constructor(private instrumenter: Instrumenter) {
|
||||
}
|
||||
|
||||
public walk(ast: ASTNode) {
|
||||
parser.visit(ast, {
|
||||
BreakStatement: (node: BreakStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
ContinueStatement: (node: ContinueStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
ContractDefinition: (node: ContractDefinition) => {
|
||||
this.instrumenter.instrumentContractDefinition(node);
|
||||
},
|
||||
EmitStatement: (node: EmitStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
ExpressionStatement: (node: ExpressionStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
FunctionDefinition: (node: FunctionDefinition) => {
|
||||
this.instrumenter.instrumentFunction(node);
|
||||
},
|
||||
IfStatement: (node: IfStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
this.instrumenter.instrumentIfStatement(node);
|
||||
},
|
||||
ModifierDefinition: (node: ModifierDefinition) => {
|
||||
this.instrumenter.instrumentFunction(node);
|
||||
},
|
||||
ReturnStatement: (node: ReturnStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
ThrowStatement: (node: ThrowStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
VariableDeclarationStatement: (node: VariableDeclarationStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
WhileStatement: (node: WhileStatement) => {
|
||||
this.instrumenter.instrumentStatement(node);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
81
src/lib/modules/coverage/instrumenter.ts
Normal file
81
src/lib/modules/coverage/instrumenter.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import {
|
||||
ContractDefinition,
|
||||
FunctionDefinition,
|
||||
IfStatement,
|
||||
Location,
|
||||
Statement,
|
||||
} from "solidity-parser-antlr";
|
||||
|
||||
import { ContractEnhanced } from "./contractEnhanced";
|
||||
import { InjectionPoint, InjectionPointType } from "./types";
|
||||
|
||||
export class Instrumenter {
|
||||
private injectionPoints: InjectionPoint[] = [];
|
||||
|
||||
constructor(private contract: ContractEnhanced) {
|
||||
}
|
||||
|
||||
public getInjectionPoints() {
|
||||
return this.injectionPoints.sort((a, b) => b.location.start.line - a.location.start.line);
|
||||
}
|
||||
|
||||
public instrumentContractDefinition(node: ContractDefinition) {
|
||||
if (!node.loc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.loc.start.line === node.loc.end.line) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addInjectionPoints("contractDefinition", 1, node.loc);
|
||||
}
|
||||
|
||||
public instrumentFunction(node: FunctionDefinition) {
|
||||
if (!node.loc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.body || !node.body.loc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.body.loc.start.line === node.body.loc.end.line) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.contract.addFunction(node.loc, node.name);
|
||||
this.addInjectionPoints("function", id, node.body.loc);
|
||||
}
|
||||
|
||||
public instrumentStatement(node: Statement) {
|
||||
if (!node.loc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.contract.addStatement(node.loc);
|
||||
this.addInjectionPoints("statement", id, node.loc);
|
||||
}
|
||||
|
||||
public instrumentIfStatement(node: IfStatement) {
|
||||
if (!node.loc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const locations = [node.trueBody, node.falseBody].reduce((acc: Location[], body) => {
|
||||
if (body && body.loc) {
|
||||
acc.push(body.loc);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const id = this.contract.addBranch(node.loc.start.line, "if", locations);
|
||||
locations.forEach((location, index) => {
|
||||
this.addInjectionPoints("branch", id, location, index);
|
||||
});
|
||||
}
|
||||
|
||||
private addInjectionPoints(type: InjectionPointType, id: number, location: Location, locationIdx?: number) {
|
||||
this.injectionPoints.push({type, id, location, locationIdx});
|
||||
}
|
||||
}
|
5
src/lib/modules/coverage/path.ts
Normal file
5
src/lib/modules/coverage/path.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import * as path from "path";
|
||||
|
||||
const fs = require("../../core/fs");
|
||||
|
||||
export const coverageContractsPath = () => path.join(fs.dappPath(), "coverage", "instrumentedContracts");
|
@ -1,63 +0,0 @@
|
||||
const EmptySourceMap = {
|
||||
createRelativeTo: function(sourceMapString) {
|
||||
if(sourceMapString === '') return EmptySourceMap;
|
||||
|
||||
return new SourceMap(sourceMapString);
|
||||
},
|
||||
toString: function() {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
class SourceMap {
|
||||
constructor(sourceMapStringOrOffset, length, id, jump) {
|
||||
if(typeof sourceMapStringOrOffset === 'string') {
|
||||
const [offset, length, id, jump] = sourceMapStringOrOffset.split(":");
|
||||
|
||||
this.offset = parseInt(offset, 10);
|
||||
this.length = parseInt(length, 10);
|
||||
|
||||
if(id) this.id = parseInt(id, 10);
|
||||
this.jump = jump;
|
||||
} else {
|
||||
this.offset = sourceMapStringOrOffset;
|
||||
this.length = length;
|
||||
this.id = id;
|
||||
this.jump = jump;
|
||||
}
|
||||
}
|
||||
|
||||
createRelativeTo(sourceMapString) {
|
||||
if(!sourceMapString) return EmptySourceMap;
|
||||
|
||||
let [offset, length, id, jump] = sourceMapString.split(":");
|
||||
|
||||
offset = (offset) ? parseInt(offset, 10) : this.offset;
|
||||
id = (id) ? parseInt(id, 10) : this.id;
|
||||
length = parseInt(length, 10);
|
||||
|
||||
return new SourceMap(offset, length, id, jump);
|
||||
}
|
||||
|
||||
subtract(sourceMap) {
|
||||
return new SourceMap(this.offset, sourceMap.offset - this.offset, this.id, this.jump);
|
||||
}
|
||||
|
||||
toString(defaultId) {
|
||||
const parts = [this.offset, this.length];
|
||||
|
||||
if(this.id !== undefined && this.id !== '') {
|
||||
parts.push(this.id);
|
||||
} else if(defaultId !== undefined) {
|
||||
parts.push(defaultId);
|
||||
}
|
||||
|
||||
return parts.join(':');
|
||||
}
|
||||
|
||||
static empty() {
|
||||
return EmptySourceMap;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SourceMap;
|
12
src/lib/modules/coverage/suppressor.ts
Normal file
12
src/lib/modules/coverage/suppressor.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { ContractEnhanced } from "./contractEnhanced";
|
||||
|
||||
export class Suppressor {
|
||||
|
||||
constructor(private contract: ContractEnhanced) {
|
||||
}
|
||||
|
||||
public process() {
|
||||
this.contract.source = this.contract.source.replace(/pure/g, "");
|
||||
this.contract.source = this.contract.source.replace(/view/g, "");
|
||||
}
|
||||
}
|
38
src/lib/modules/coverage/types.ts
Normal file
38
src/lib/modules/coverage/types.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { Location } from "solidity-parser-antlr";
|
||||
|
||||
export type InjectionPointType = "statement" | "branch" | "function" | "contractDefinition";
|
||||
export type BranchType = "if" | "switch";
|
||||
|
||||
export interface InjectionPoint {
|
||||
type: InjectionPointType;
|
||||
id: number;
|
||||
location: Location;
|
||||
locationIdx?: number;
|
||||
}
|
||||
|
||||
export interface Coverage {
|
||||
b: { [branchId: number]: number[] };
|
||||
branchMap: {
|
||||
[branchId: number]: {
|
||||
line: number;
|
||||
locations: Location[];
|
||||
type: BranchType;
|
||||
};
|
||||
};
|
||||
code: string;
|
||||
f: { [functionId: number]: number };
|
||||
fnMap: {
|
||||
[functionId: number]: {
|
||||
line: number;
|
||||
loc: Location;
|
||||
name: string;
|
||||
skip?: boolean;
|
||||
};
|
||||
};
|
||||
l: { [line: number]: number };
|
||||
path: string;
|
||||
s: { [statementId: number]: number };
|
||||
statementMap: {
|
||||
[statementId: number]: Location;
|
||||
};
|
||||
}
|
@ -8,7 +8,6 @@ class Solidity {
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.ipc = options.ipc;
|
||||
this.contractDirectories = embark.config.contractDirectories;
|
||||
this.solcAlreadyLoaded = false;
|
||||
this.solcW = null;
|
||||
this.useDashboard = options.useDashboard;
|
||||
@ -169,7 +168,7 @@ class Solidity {
|
||||
function (file, fileCb) {
|
||||
let filename = file.filename;
|
||||
|
||||
for (let directory of self.contractDirectories) {
|
||||
for (let directory of self.embark.config.contractDirectories) {
|
||||
let match = new RegExp("^" + directory);
|
||||
filename = filename.replace(match, '');
|
||||
}
|
||||
|
@ -89,13 +89,13 @@ class TestRunner {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
console.info(`Coverage report created. You can find it here: ${fs.dappPath('coverage/__root__/index.html')}\n`);
|
||||
console.info(`Coverage report created. You can find it here: ${fs.dappPath('coverage/index.html')}\n`);
|
||||
const opn = require('opn');
|
||||
const _next = () => { next(null, results); };
|
||||
if (options.noBrowser) {
|
||||
return next(null, results);
|
||||
}
|
||||
opn(fs.dappPath('coverage/__root__/index.html'), {wait: false})
|
||||
opn(fs.dappPath('coverage/index.html'), {wait: false})
|
||||
.then(() => new Promise(resolve => setTimeout(resolve, 1000)))
|
||||
.then(_next, _next);
|
||||
});
|
||||
@ -185,11 +185,12 @@ class TestRunner {
|
||||
let fns = files.map((file) => {
|
||||
return (cb) => {
|
||||
const mocha = new Mocha();
|
||||
const gasLimit = options.coverage ? constants.tests.coverageGasLimit : constants.tests.gasLimit;
|
||||
const reporter = options.inProcess ? EmbarkApiSpec : EmbarkSpec;
|
||||
mocha.reporter(reporter, {
|
||||
events: self.events,
|
||||
gasDetails: options.gasDetails,
|
||||
gasLimit: constants.tests.gasLimit
|
||||
gasLimit
|
||||
});
|
||||
|
||||
mocha.addFile(file);
|
||||
|
@ -227,7 +227,13 @@ class Test {
|
||||
});
|
||||
}
|
||||
|
||||
_deploy(config, callback) {
|
||||
async deploy(contract, deployArgs = {}, sendArgs = {}) {
|
||||
const instance = await contract.deploy(deployArgs).send(sendArgs);
|
||||
this.events.emit("tests:manualDeploy", instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
async _deploy(config, callback) {
|
||||
const self = this;
|
||||
async.waterfall([
|
||||
function getConfig(next) {
|
||||
|
@ -1,279 +0,0 @@
|
||||
/*global describe, it*/
|
||||
const {assert} = require('chai');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sinon = require('sinon');
|
||||
|
||||
const ContractSources = require('../lib/modules/coverage/contractSources');
|
||||
const ContractSource = require('../lib/modules/coverage/contractSource');
|
||||
const SourceMap = require('../lib/modules/coverage/sourceMap');
|
||||
|
||||
function fixturePath(fixture) {
|
||||
return path.join(__dirname, 'fixtures', fixture);
|
||||
}
|
||||
|
||||
function loadFixture(fixture) {
|
||||
return fs.readFileSync(fixturePath(fixture)).toString();
|
||||
}
|
||||
|
||||
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']);
|
||||
}, /ENOENT: no such file or directory, open/);
|
||||
|
||||
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', '/tmp/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 deployed 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.contractDeployedBytecode);
|
||||
assert.isNotEmpty(contractSource.contractDeployedBytecode['x']);
|
||||
|
||||
var bytecode = contractSource.contractDeployedBytecode['x'];
|
||||
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: {offset: 26, length: 487, id: 0, jump: '-'}, jump: '-', seen: false}, bytecode[0]);
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: SourceMap.empty(), seen: false, jump: undefined}, bytecode[2]);
|
||||
assert.deepEqual({instruction: 'MSTORE', sourceMap: SourceMap.empty(), seen: false, jump: undefined}, bytecode[4]);
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: SourceMap.empty(), seen: false, jump: undefined}, bytecode[5]);
|
||||
|
||||
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: {offset: 26, length: 487, id: 0, jump: '-'}, jump: '-', seen: false}, bytecode[0]);
|
||||
assert.deepEqual({instruction: 'PUSH1', sourceMap: SourceMap.empty(), seen: false, jump: undefined}, bytecode[2]);
|
||||
assert.deepEqual({instruction: 'MSTORE', sourceMap: SourceMap.empty(), seen: false, jump: undefined}, bytecode[4]);
|
||||
assert.deepEqual({instruction: 'CALLVALUE', sourceMap: {offset: 71, length: 60, jump: undefined}, seen: false, jump: undefined}, 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);
|
||||
assert.exists(coverage);
|
||||
|
||||
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,0], coverage.b['61']);
|
||||
assert.equal(6, 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();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createRelativeTo', () => {
|
||||
it('should return an empty source map on an empty string', (done) => {
|
||||
var sm1 = new SourceMap('192:10:0');
|
||||
var sm2 = sm1.createRelativeTo('');
|
||||
|
||||
assert.equal('', sm2.toString());
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return the correct source map on a relative string', (done) => {
|
||||
var sm1 = new SourceMap('192:10:0');
|
||||
var sm2 = sm1.createRelativeTo(':14');
|
||||
|
||||
assert.equal(192, sm2.offset);
|
||||
assert.equal(14, sm2.length);
|
||||
assert.equal(0, sm2.id);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
1
src/typings/contract.d.ts
vendored
1
src/typings/contract.d.ts
vendored
@ -2,5 +2,6 @@ import { ABIDefinition } from "web3/eth/abi";
|
||||
|
||||
export interface Contract {
|
||||
abiDefinition: ABIDefinition[];
|
||||
deployedAddress: string;
|
||||
className: string;
|
||||
}
|
||||
|
2
src/typings/embark.d.ts
vendored
2
src/typings/embark.d.ts
vendored
@ -14,12 +14,14 @@ export interface Embark {
|
||||
registerConsoleCommand: any;
|
||||
logger: Logger;
|
||||
config: {
|
||||
contractsFiles: any[];
|
||||
embarkConfig: {
|
||||
contracts: string[] | string;
|
||||
config: {
|
||||
contracts: string;
|
||||
};
|
||||
};
|
||||
reloadConfig(): void;
|
||||
};
|
||||
registerActionForEvent(name: string, action: (callback: () => void) => void): void;
|
||||
}
|
||||
|
332
src/typings/solidity-parser-antlr/index.d.ts
vendored
Normal file
332
src/typings/solidity-parser-antlr/index.d.ts
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
declare module "solidity-parser-antlr" {
|
||||
export interface LineColumn {
|
||||
line: number;
|
||||
column: number;
|
||||
}
|
||||
export interface Location {
|
||||
start: LineColumn;
|
||||
end: LineColumn;
|
||||
}
|
||||
export interface BaseASTNode {
|
||||
type: string;
|
||||
range?: [number, number];
|
||||
loc?: Location;
|
||||
}
|
||||
export interface SourceUnit extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface PragmaDirective extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface PragmaName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface PragmaValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Version extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface VersionOperator extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface VersionConstraint extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ImportDeclaration extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ImportDirective extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ContractDefinition extends BaseASTNode {
|
||||
name: string;
|
||||
}
|
||||
export interface InheritanceSpecifier extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ContractPart extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface StateVariableDeclaration extends BaseASTNode {
|
||||
variables: VariableDeclaration[];
|
||||
}
|
||||
export interface UsingForDeclaration extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface StructDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ModifierDefinition extends BaseASTNode {
|
||||
name: string;
|
||||
}
|
||||
export interface ModifierInvocation extends BaseASTNode {
|
||||
name: string;
|
||||
}
|
||||
export interface FunctionDefinition extends BaseASTNode {
|
||||
name: string;
|
||||
body?: Block;
|
||||
}
|
||||
export interface ReturnParameters extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ModifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EventDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EnumValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EnumDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Parameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EventParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EventParameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface FunctionTypeParameterList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface FunctionTypeParameter extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface VariableDeclaration extends BaseASTNode {
|
||||
visibility: "public" | "private";
|
||||
isStateVar: boolean;
|
||||
}
|
||||
export interface TypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface UserDefinedTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Mapping extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface FunctionTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface StorageLocation extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface StateMutability extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Block extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Statement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface EmitStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ExpressionStatement extends BaseASTNode {
|
||||
expression: ASTNode;
|
||||
}
|
||||
export interface IfStatement extends BaseASTNode {
|
||||
trueBody: ASTNode;
|
||||
falseBody: ASTNode;
|
||||
}
|
||||
export interface WhileStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface SimpleStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ForStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface InlineAssemblyStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface DoWhileStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ContinueStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface BreakStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ReturnStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ThrowStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface VariableDeclarationStatement extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface IdentifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ElementaryTypeName extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Expression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface PrimaryExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ExpressionList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface NameValueList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface NameValue extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface FunctionCallArguments extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyBlock extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyItem extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyCall extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyLocalDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyAssignment extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyIdentifierOrList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyIdentifierList extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyStackAssignment extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface LabelDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblySwitch extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyCase extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyFunctionDefinition extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyFunctionReturns extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyFor extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyIf extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface AssemblyLiteral extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface SubAssembly extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface TupleExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface ElementaryTypeNameExpression extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface NumberLiteral extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export interface Identifier extends BaseASTNode {} // tslint:disable-line:no-empty-interface
|
||||
export type BinOp =
|
||||
| "+"
|
||||
| "-"
|
||||
| "*"
|
||||
| "/"
|
||||
| "**"
|
||||
| "%"
|
||||
| "<<"
|
||||
| ">>"
|
||||
| "&&"
|
||||
| "||"
|
||||
| "&"
|
||||
| "|"
|
||||
| "^"
|
||||
| "<"
|
||||
| ">"
|
||||
| "<="
|
||||
| ">="
|
||||
| "=="
|
||||
| "!="
|
||||
| "="
|
||||
| "|="
|
||||
| "^="
|
||||
| "&="
|
||||
| "<<="
|
||||
| ">>="
|
||||
| "+="
|
||||
| "-="
|
||||
| "*="
|
||||
| "/="
|
||||
| "%=";
|
||||
export interface BinaryOperation extends BaseASTNode {
|
||||
left: ASTNode;
|
||||
right: ASTNode;
|
||||
operator: BinOp;
|
||||
}
|
||||
export interface Conditional extends BaseASTNode {
|
||||
trueExpression: ASTNode;
|
||||
falseExpression: ASTNode;
|
||||
}
|
||||
|
||||
export type ASTNode =
|
||||
| SourceUnit
|
||||
| PragmaDirective
|
||||
| PragmaName
|
||||
| PragmaValue
|
||||
| Version
|
||||
| VersionOperator
|
||||
| VersionConstraint
|
||||
| ImportDeclaration
|
||||
| ImportDirective
|
||||
| ContractDefinition
|
||||
| InheritanceSpecifier
|
||||
| ContractPart
|
||||
| StateVariableDeclaration
|
||||
| UsingForDeclaration
|
||||
| StructDefinition
|
||||
| ModifierDefinition
|
||||
| ModifierInvocation
|
||||
| FunctionDefinition
|
||||
| ReturnParameters
|
||||
| ModifierList
|
||||
| EventDefinition
|
||||
| EnumValue
|
||||
| EnumDefinition
|
||||
| ParameterList
|
||||
| Parameter
|
||||
| EventParameterList
|
||||
| EventParameter
|
||||
| FunctionTypeParameterList
|
||||
| FunctionTypeParameter
|
||||
| VariableDeclaration
|
||||
| TypeName
|
||||
| UserDefinedTypeName
|
||||
| Mapping
|
||||
| FunctionTypeName
|
||||
| StorageLocation
|
||||
| StateMutability
|
||||
| Block
|
||||
| Statement
|
||||
| EmitStatement
|
||||
| ExpressionStatement
|
||||
| IfStatement
|
||||
| WhileStatement
|
||||
| SimpleStatement
|
||||
| ForStatement
|
||||
| InlineAssemblyStatement
|
||||
| DoWhileStatement
|
||||
| ContinueStatement
|
||||
| BreakStatement
|
||||
| ReturnStatement
|
||||
| ThrowStatement
|
||||
| VariableDeclarationStatement
|
||||
| IdentifierList
|
||||
| ElementaryTypeName
|
||||
| Expression
|
||||
| PrimaryExpression
|
||||
| ExpressionList
|
||||
| NameValueList
|
||||
| NameValue
|
||||
| FunctionCallArguments
|
||||
| AssemblyBlock
|
||||
| AssemblyItem
|
||||
| AssemblyExpression
|
||||
| AssemblyCall
|
||||
| AssemblyLocalDefinition
|
||||
| AssemblyAssignment
|
||||
| AssemblyIdentifierOrList
|
||||
| AssemblyIdentifierList
|
||||
| AssemblyStackAssignment
|
||||
| LabelDefinition
|
||||
| AssemblySwitch
|
||||
| AssemblyCase
|
||||
| AssemblyFunctionDefinition
|
||||
| AssemblyFunctionReturns
|
||||
| AssemblyFor
|
||||
| AssemblyIf
|
||||
| AssemblyLiteral
|
||||
| SubAssembly
|
||||
| TupleExpression
|
||||
| ElementaryTypeNameExpression
|
||||
| NumberLiteral
|
||||
| Identifier
|
||||
| BinaryOperation
|
||||
| Conditional;
|
||||
export interface Visitor {
|
||||
SourceUnit?: (node: SourceUnit) => void;
|
||||
PragmaDirective?: (node: PragmaDirective) => void;
|
||||
PragmaName?: (node: PragmaName) => void;
|
||||
PragmaValue?: (node: PragmaValue) => void;
|
||||
Version?: (node: Version) => void;
|
||||
VersionOperator?: (node: VersionOperator) => void;
|
||||
VersionConstraint?: (node: VersionConstraint) => void;
|
||||
ImportDeclaration?: (node: ImportDeclaration) => void;
|
||||
ImportDirective?: (node: ImportDirective) => void;
|
||||
ContractDefinition?: (node: ContractDefinition) => void;
|
||||
InheritanceSpecifier?: (node: InheritanceSpecifier) => void;
|
||||
ContractPart?: (node: ContractPart) => void;
|
||||
StateVariableDeclaration?: (node: StateVariableDeclaration) => void;
|
||||
UsingForDeclaration?: (node: UsingForDeclaration) => void;
|
||||
StructDefinition?: (node: StructDefinition) => void;
|
||||
ModifierDefinition?: (node: ModifierDefinition) => void;
|
||||
ModifierInvocation?: (node: ModifierInvocation) => void;
|
||||
FunctionDefinition?: (node: FunctionDefinition) => void;
|
||||
ReturnParameters?: (node: ReturnParameters) => void;
|
||||
ModifierList?: (node: ModifierList) => void;
|
||||
EventDefinition?: (node: EventDefinition) => void;
|
||||
EnumValue?: (node: EnumValue) => void;
|
||||
EnumDefinition?: (node: EnumDefinition) => void;
|
||||
ParameterList?: (node: ParameterList) => void;
|
||||
Parameter?: (node: Parameter) => void;
|
||||
EventParameterList?: (node: EventParameterList) => void;
|
||||
EventParameter?: (node: EventParameter) => void;
|
||||
FunctionTypeParameterList?: (node: FunctionTypeParameterList) => void;
|
||||
FunctionTypeParameter?: (node: FunctionTypeParameter) => void;
|
||||
VariableDeclaration?: (node: VariableDeclaration) => void;
|
||||
TypeName?: (node: TypeName) => void;
|
||||
UserDefinedTypeName?: (node: UserDefinedTypeName) => void;
|
||||
Mapping?: (node: Mapping) => void;
|
||||
FunctionTypeName?: (node: FunctionTypeName) => void;
|
||||
StorageLocation?: (node: StorageLocation) => void;
|
||||
StateMutability?: (node: StateMutability) => void;
|
||||
Block?: (node: Block) => void;
|
||||
Statement?: (node: Statement) => void;
|
||||
EmitStatement?: (node: Statement) => void;
|
||||
ExpressionStatement?: (node: ExpressionStatement) => void;
|
||||
IfStatement?: (node: IfStatement) => void;
|
||||
WhileStatement?: (node: WhileStatement) => void;
|
||||
SimpleStatement?: (node: SimpleStatement) => void;
|
||||
ForStatement?: (node: ForStatement) => void;
|
||||
InlineAssemblyStatement?: (node: InlineAssemblyStatement) => void;
|
||||
DoWhileStatement?: (node: DoWhileStatement) => void;
|
||||
ContinueStatement?: (node: ContinueStatement) => void;
|
||||
BreakStatement?: (node: BreakStatement) => void;
|
||||
ReturnStatement?: (node: ReturnStatement) => void;
|
||||
ThrowStatement?: (node: ThrowStatement) => void;
|
||||
VariableDeclarationStatement?: (node: VariableDeclarationStatement) => void;
|
||||
IdentifierList?: (node: IdentifierList) => void;
|
||||
ElementaryTypeName?: (node: ElementaryTypeName) => void;
|
||||
Expression?: (node: Expression) => void;
|
||||
PrimaryExpression?: (node: PrimaryExpression) => void;
|
||||
ExpressionList?: (node: ExpressionList) => void;
|
||||
NameValueList?: (node: NameValueList) => void;
|
||||
NameValue?: (node: NameValue) => void;
|
||||
FunctionCallArguments?: (node: FunctionCallArguments) => void;
|
||||
AssemblyBlock?: (node: AssemblyBlock) => void;
|
||||
AssemblyItem?: (node: AssemblyItem) => void;
|
||||
AssemblyExpression?: (node: AssemblyExpression) => void;
|
||||
AssemblyCall?: (node: AssemblyCall) => void;
|
||||
AssemblyLocalDefinition?: (node: AssemblyLocalDefinition) => void;
|
||||
AssemblyAssignment?: (node: AssemblyAssignment) => void;
|
||||
AssemblyIdentifierOrList?: (node: AssemblyIdentifierOrList) => void;
|
||||
AssemblyIdentifierList?: (node: AssemblyIdentifierList) => void;
|
||||
AssemblyStackAssignment?: (node: AssemblyStackAssignment) => void;
|
||||
LabelDefinition?: (node: LabelDefinition) => void;
|
||||
AssemblySwitch?: (node: AssemblySwitch) => void;
|
||||
AssemblyCase?: (node: AssemblyCase) => void;
|
||||
AssemblyFunctionDefinition?: (node: AssemblyFunctionDefinition) => void;
|
||||
AssemblyFunctionReturns?: (node: AssemblyFunctionReturns) => void;
|
||||
AssemblyFor?: (node: AssemblyFor) => void;
|
||||
AssemblyIf?: (node: AssemblyIf) => void;
|
||||
AssemblyLiteral?: (node: AssemblyLiteral) => void;
|
||||
SubAssembly?: (node: SubAssembly) => void;
|
||||
TupleExpression?: (node: TupleExpression) => void;
|
||||
ElementaryTypeNameExpression?: (node: ElementaryTypeNameExpression) => void;
|
||||
NumberLiteral?: (node: NumberLiteral) => void;
|
||||
Identifier?: (node: Identifier) => void;
|
||||
BinaryOperation?: (node: BinaryOperation) => void;
|
||||
Conditional?: (node: Conditional) => void;
|
||||
}
|
||||
export interface ParserOpts {
|
||||
tolerant?: boolean;
|
||||
range?: boolean;
|
||||
loc?: boolean;
|
||||
}
|
||||
export function parse(sourceCode: string, parserOpts: ParserOpts): ASTNode;
|
||||
export function visit(ast: ASTNode, visitor: Visitor): void;
|
||||
}
|
@ -15,4 +15,4 @@ contract SimpleStorage {
|
||||
return storedData;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import SimpleStorage from 'Embark/contracts/SimpleStorage';
|
||||
import React from 'react';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
|
||||
class Blockchain extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
valueSet: 10,
|
||||
valueGet: "",
|
||||
logs: []
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e){
|
||||
this.setState({valueSet: e.target.value});
|
||||
}
|
||||
|
||||
setValue(e){
|
||||
e.preventDefault();
|
||||
|
||||
var value = parseInt(this.state.valueSet, 10);
|
||||
|
||||
SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount});
|
||||
this._addToLog("SimpleStorage.methods.set(value).send({from: web3.eth.defaultAccount})");
|
||||
}
|
||||
|
||||
getValue(e){
|
||||
e.preventDefault();
|
||||
|
||||
SimpleStorage.methods.get().call()
|
||||
.then(_value => this.setState({valueGet: _value}));
|
||||
this._addToLog("SimpleStorage.methods.get(console.log)");
|
||||
}
|
||||
|
||||
_addToLog(txt){
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
render(){
|
||||
return (<React.Fragment>
|
||||
<h3> 1. Set the value in the blockchain</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueSet}
|
||||
onChange={(e) => this.handleChange(e)} />
|
||||
<Button bsStyle="primary" onClick={(e) => this.setValue(e)}>Set Value</Button>
|
||||
<HelpBlock>Once you set the value, the transaction will need to be mined and then the value will be updated on the blockchain.</HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 2. Get the current value</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<HelpBlock>current value is <span className="value">{this.state.valueGet}</span></HelpBlock>
|
||||
<Button bsStyle="primary" onClick={(e) => this.getValue(e)}>Get Value</Button>
|
||||
<HelpBlock>Click the button to get the current value. The initial value is 100.</HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 3. Contract Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Blockchain;
|
@ -1,172 +0,0 @@
|
||||
/*global web3*/
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import { Alert, Form, FormGroup, FormControl, Button } from 'react-bootstrap';
|
||||
|
||||
window.EmbarkJS = EmbarkJS;
|
||||
|
||||
class ENS extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
valueResolve: 'embark.eth',
|
||||
responseResolve: null,
|
||||
isResolveError: false,
|
||||
valueLookup: '',
|
||||
responseLookup: null,
|
||||
isLookupError: false,
|
||||
valueRegister: '',
|
||||
addressRegister: '',
|
||||
responseRegister: null,
|
||||
isRegisterError: false,
|
||||
embarkLogs: []
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EmbarkJS.onReady(() => {
|
||||
if (!web3.eth.defaultAccount) {
|
||||
this.setState({
|
||||
globalError: 'There is currently no default account. If Metamask is active, please sign in or deactivate it.'
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
addressRegister: web3.eth.defaultAccount,
|
||||
valueLookup: web3.eth.defaultAccount
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleChange(stateName, e) {
|
||||
this.setState({ [stateName]: e.target.value });
|
||||
}
|
||||
|
||||
registerSubDomain(e) {
|
||||
e.preventDefault();
|
||||
const self = this;
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.registerSubDomain('${this.state.valueRegister}', '${this.state.addressRegister}', console.log)`);
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
|
||||
EmbarkJS.Names.registerSubDomain(this.state.valueRegister, this.state.addressRegister, (err, transaction) => {
|
||||
const message = err ? err : `Successfully registered "${this.state.valueRegister}" with ${transaction.gasUsed} gas`;
|
||||
self.setState({
|
||||
responseRegister: message,
|
||||
isRegisterError: !!err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resolveName(e) {
|
||||
e.preventDefault();
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueResolve}', console.log)`);
|
||||
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseResolve: err.message || err,
|
||||
isResolveError: true
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
responseResolve: result,
|
||||
isResolveError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
lookupAddress(e) {
|
||||
e.preventDefault();
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueLookup}', console.log)`);
|
||||
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseLookup: err.message || err,
|
||||
isLookupError: true
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
responseLookup: result,
|
||||
isLookupError: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<React.Fragment>
|
||||
{this.state.globalError && <Alert bsStyle="danger">{this.state.globalError}</Alert>}
|
||||
<h3>Resolve a name</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
{this.state.responseResolve &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isResolveError ? 'danger' : 'success'}>
|
||||
Resolved address: <span className="value">{this.state.responseResolve}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueResolve}
|
||||
onChange={(e) => this.handleChange('valueResolve', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.resolveName(e)}>Resolve name</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Lookup an address</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
{this.state.responseLookup &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isLookupError ? 'danger' : 'success'}>
|
||||
Looked up domain: <span className="value">{this.state.responseLookup}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueLookup}
|
||||
onChange={(e) => this.handleChange('valueLookup', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.lookupAddress(e)}>Lookup address</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Register subdomain for embark</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
{this.state.responseRegister &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseRegister}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueRegister}
|
||||
onChange={(e) => this.handleChange('valueRegister', e)}/>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.addressRegister}
|
||||
onChange={(e) => this.handleChange('addressRegister', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.registerSubDomain(e)}>Register subdomain</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Embark Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.embarkLogs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ENS;
|
@ -1,258 +0,0 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import {Alert, Form, FormGroup, FormControl, HelpBlock, Button} from 'react-bootstrap';
|
||||
|
||||
class Storage extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
textToSave: 'hello world!',
|
||||
generatedHash: '',
|
||||
loadText: '',
|
||||
storedText: '',
|
||||
fileToUpload: null,
|
||||
fileHash: '',
|
||||
imageToDownload: '',
|
||||
url: '',
|
||||
logs: [],
|
||||
storageError: '',
|
||||
valueRegister: '',
|
||||
valueResolver: '',
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(e, name) {
|
||||
this.state[name] = e.target.value;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
handleFileUpload(e) {
|
||||
this.setState({fileToUpload: [e.target]});
|
||||
}
|
||||
|
||||
addToLog(txt) {
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
setText(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.saveText(this.state.textToSave)
|
||||
.then((hash) => {
|
||||
this.setState({
|
||||
generatedHash: hash,
|
||||
loadText: hash,
|
||||
storageError: ''
|
||||
});
|
||||
this.addToLog("EmbarkJS.Storage.saveText('" + this.state.textToSave + "').then(function(hash) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage saveText Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadHash(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.get(this.state.loadText)
|
||||
.then((content) => {
|
||||
this.setState({storedText: content, storageError: ''});
|
||||
this.addToLog("EmbarkJS.Storage.get('" + this.state.loadText + "').then(function(content) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage get Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uploadFile(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EmbarkJS.Storage.uploadFile(this.state.fileToUpload)
|
||||
.then((hash) => {
|
||||
this.setState({
|
||||
fileHash: hash,
|
||||
imageToDownload: hash,
|
||||
storageError: ''
|
||||
});
|
||||
this.addToLog("EmbarkJS.Storage.uploadFile(this.state.fileToUpload).then(function(hash) { })");
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
this.setState({storageError: err.message});
|
||||
console.log("Storage uploadFile Error => " + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadFile(e) {
|
||||
let _url = EmbarkJS.Storage.getUrl(this.state.imageToDownload);
|
||||
this.setState({url: _url});
|
||||
this.addToLog("EmbarkJS.Storage.getUrl('" + this.state.imageToDownload + "')");
|
||||
}
|
||||
|
||||
ipnsRegister(e) {
|
||||
e.preventDefault();
|
||||
this.setState({ registering: true, responseRegister: false });
|
||||
this.addToLog("EmbarkJS.Names.register(this.state.ipfsHash).then(function(hash) { })");
|
||||
EmbarkJS.Names.register(this.state.valueRegister, (err, name) => {
|
||||
let responseRegister;
|
||||
let isRegisterError = false;
|
||||
if (err) {
|
||||
isRegisterError = true;
|
||||
responseRegister = "Name Register Error: " + (err.message || err)
|
||||
} else {
|
||||
responseRegister = name;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
registering: false,
|
||||
responseRegister,
|
||||
isRegisterError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ipnsResolve(e) {
|
||||
e.preventDefault();
|
||||
this.setState({ resolving: true, responseResolver: false });
|
||||
this.addToLog("EmbarkJS.Names.resolve(this.state.ipnsName, function(err, path) { })");
|
||||
EmbarkJS.Names.resolve(this.state.valueResolver, (err, path) => {
|
||||
let responseResolver;
|
||||
let isResolverError = false;
|
||||
if (err) {
|
||||
isResolverError = true;
|
||||
responseResolver = "Name Resolve Error: " + (err.message || err)
|
||||
} else {
|
||||
responseResolver = path;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
resolving: false,
|
||||
responseResolver,
|
||||
isResolverError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <React.Fragment>
|
||||
{
|
||||
!this.props.enabled ?
|
||||
<React.Fragment>
|
||||
<Alert bsStyle="warning">The node you are using does not support IPFS. Please ensure <a
|
||||
href="https://github.com/ipfs/js-ipfs-api#cors" target="_blank">CORS</a> is setup for the IPFS
|
||||
node.</Alert>
|
||||
</React.Fragment> : ''
|
||||
}
|
||||
{
|
||||
this.state.storageError !== '' ?
|
||||
<Alert bsStyle="danger">{this.state.storageError}</Alert>
|
||||
: ''
|
||||
}
|
||||
<h3>Save text to storage</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.textToSave}
|
||||
onChange={e => this.handleChange(e, 'textToSave')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.setText(e)}>Save Text</Button>
|
||||
<HelpBlock>generated Hash: <span className="textHash">{this.state.generatedHash}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Load text from storage given an hash</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.loadText}
|
||||
onChange={e => this.handleChange(e, 'loadText')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.loadHash(e)}>Load</Button>
|
||||
<HelpBlock>result: <span className="textHash">{this.state.storedText}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Upload file to storage</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="file"
|
||||
onChange={(e) => this.handleFileUpload(e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.uploadFile(e)}>Upload</Button>
|
||||
<HelpBlock>generated hash: <span className="fileHash">{this.state.fileHash}</span></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Get file or image from storage</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.imageToDownload}
|
||||
onChange={e => this.handleChange(e, 'imageToDownload')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.loadFile(e)}>Download</Button>
|
||||
<HelpBlock>file available at: <span><a href={this.state.url}
|
||||
target="_blank">{this.state.url}</a></span></HelpBlock>
|
||||
<HelpBlock><img src={this.state.url}/></HelpBlock>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Register to IPNS</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.valueRegister}
|
||||
onChange={e => this.handleChange(e, 'valueRegister')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.ipnsRegister(e)}>
|
||||
{this.state.registering ? 'Registering...' : 'Register' }
|
||||
</Button>
|
||||
<HelpBlock>It will take around 1 minute</HelpBlock>
|
||||
{this.state.responseRegister &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseRegister}</span>
|
||||
</Alert>}
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Resolve name</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
value={this.state.valueResolver}
|
||||
onChange={e => this.handleChange(e, 'valueResolver')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.ipnsResolve(e)}>
|
||||
{this.state.resolving ? 'Resolving...' : 'Resolve' }
|
||||
</Button>
|
||||
<HelpBlock>It will take around 1 minute</HelpBlock>
|
||||
{this.state.responseResolver &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isResolverError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseResolver}</span>
|
||||
</Alert>}
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
<p>EmbarkJS.Storage.setProvider('ipfs',{'{'}server: 'localhost', port: '5001'{'}'})</p>
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Storage;
|
@ -1,118 +0,0 @@
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import {Alert, Form, FormGroup, FormControl, Button} from 'react-bootstrap';
|
||||
|
||||
class Whisper extends React.Component {
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
listenTo: '',
|
||||
channel: '',
|
||||
message: '',
|
||||
subscribedChannels: [],
|
||||
messageList: [],
|
||||
logs: []
|
||||
};
|
||||
}
|
||||
|
||||
handleChange (e, name) {
|
||||
this.state[name] = e.target.value;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
sendMessage (e) {
|
||||
e.preventDefault();
|
||||
EmbarkJS.Messages.sendMessage({topic: this.state.channel, data: this.state.message});
|
||||
this.addToLog("EmbarkJS.Messages.sendMessage({topic: '" + this.state.channel + "', data: '" + this.state.message + "'})");
|
||||
}
|
||||
|
||||
listenToChannel (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const subscribedChannels = this.state.subscribedChannels;
|
||||
subscribedChannels.push(<span>Subscribed to <b>{this.state.listenTo}</b>. Now try sending a message</span>);
|
||||
this.setState({
|
||||
subscribedChannels
|
||||
});
|
||||
|
||||
EmbarkJS.Messages.listenTo({topic: [this.state.listenTo]}, (error, message) => {
|
||||
const messageList = this.state.messageList;
|
||||
if (error) {
|
||||
messageList.push(<span className="alert-danger">Error: {error}</span>);
|
||||
} else {
|
||||
messageList.push(<span>Channel: <b>{message.topic}</b> | Message: <b>{message.data}</b></span>);
|
||||
}
|
||||
this.setState({
|
||||
messageList
|
||||
});
|
||||
});
|
||||
|
||||
this.addToLog("EmbarkJS.Messages.listenTo({topic: ['" + this.state.listenTo + "']}).then(function(message) {})");
|
||||
}
|
||||
|
||||
addToLog (txt) {
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{
|
||||
!this.props.enabled ?
|
||||
<React.Fragment>
|
||||
<Alert bsStyle="warning">The node you are using does not support Whisper</Alert>
|
||||
<Alert bsStyle="warning">The node uses an unsupported version of Whisper</Alert>
|
||||
</React.Fragment> : ''
|
||||
}
|
||||
<h3>Listen To channel</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.listenTo}
|
||||
placeholder="channel"
|
||||
onChange={e => this.handleChange(e, 'listenTo')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.listenToChannel(e)}>Start Listening</Button>
|
||||
<div id="subscribeList">
|
||||
{this.state.subscribedChannels.map((item, i) => <p key={i}>{item}</p>)}
|
||||
</div>
|
||||
<p>messages received:</p>
|
||||
<div id="messagesList">
|
||||
{this.state.messageList.map((item, i) => <p key={i}>{item}</p>)}
|
||||
</div>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Send Message</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.channel}
|
||||
placeholder="channel"
|
||||
onChange={e => this.handleChange(e, 'channel')}/>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.message}
|
||||
placeholder="message"
|
||||
onChange={e => this.handleChange(e, 'message')}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.sendMessage(e)}>Send Message</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
<p>EmbarkJS.Messages.setProvider('whisper')</p>
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Whisper;
|
@ -1,57 +0,0 @@
|
||||
|
||||
div {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
background-color: black;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: red;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: mediumseagreen;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.alert-result {
|
||||
margin-left: 0;
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {Tabs, Tab} from 'react-bootstrap';
|
||||
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import Blockchain from './components/blockchain';
|
||||
import Whisper from './components/whisper';
|
||||
import Storage from './components/storage';
|
||||
import ENS from './components/ens';
|
||||
|
||||
import './dapp.css';
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
|
||||
this.state = {
|
||||
activeKey: 1,
|
||||
whisperEnabled: false,
|
||||
storageEnabled: false,
|
||||
ensEnabled: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
EmbarkJS.onReady(() => {
|
||||
EmbarkJS.Messages.Providers.whisper.getWhisperVersion((err, _version) => {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
this.setState({whisperEnabled: true});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_renderStatus(title, available) {
|
||||
let className = available ? 'pull-right status-online' : 'pull-right status-offline';
|
||||
return <React.Fragment>
|
||||
{title}
|
||||
<span className={className}></span>
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
||||
handleSelect(key) {
|
||||
if (key === 2) {
|
||||
EmbarkJS.Names.setProvider('ipns', {server: 'localhost', port: '5001'});
|
||||
} else if (key === 4) {
|
||||
EmbarkJS.Names.currentNameSystems = this.state.ensNameSystems
|
||||
}
|
||||
this.setState({ activeKey: key });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div><h3>Embark - Usage Example</h3>
|
||||
<Tabs onSelect={this.handleSelect} activeKey={this.state.activeKey} id="uncontrolled-tab-example">
|
||||
<Tab eventKey={1} title="Blockchain">
|
||||
<Blockchain/>
|
||||
</Tab>
|
||||
<Tab eventKey={2} title={this._renderStatus('Decentralized Storage', this.state.storageEnabled)}>
|
||||
<Storage enabled={this.state.storageEnabled}/>
|
||||
</Tab>
|
||||
<Tab eventKey={3} title={this._renderStatus('P2P communication (Whisper)', this.state.whisperEnabled)}>
|
||||
<Whisper enabled={this.state.whisperEnabled}/>
|
||||
</Tab>
|
||||
<Tab eventKey={4} title={this._renderStatus('Naming (ENS)', this.state.ensEnabled)}>
|
||||
<ENS enabled={this.state.ensEnabled}/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App></App>, document.getElementById('app'));
|
@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Embark - SimpleStorage Demo</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body class="container">
|
||||
<div id="app">
|
||||
</div>
|
||||
<script src="js/dapp.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,79 +0,0 @@
|
||||
module.exports = {
|
||||
development: {
|
||||
enabled: true,
|
||||
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
|
||||
networkId: "1337", // Network id used when networkType is custom
|
||||
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
|
||||
datadir: ".embark/development/datadir", // Data directory for the databases and keystore
|
||||
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
|
||||
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
|
||||
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
|
||||
rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost")
|
||||
rpcPort: 8545, // HTTP-RPC server listening port (default: 8545)
|
||||
rpcCorsDomain: "auto", // Comma separated list of domains from which to accept cross origin requests (browser enforced)
|
||||
// When set to "auto", Embark will automatically set the cors to the address of the webserver
|
||||
proxy: true, // Proxy is used to present meaningful information about transactions
|
||||
targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine
|
||||
wsRPC: true, // Enable the WS-RPC server
|
||||
wsOrigins: "http://localhost:8000,http://localhost:8080,embark", // Origins from which to accept websockets requests
|
||||
// When set to "auto", Embark will automatically set the cors to the address of the webserver
|
||||
wsHost: "localhost", // WS-RPC server listening interface (default: "localhost")
|
||||
wsPort: 8546, // WS-RPC server listening port (default: 8546)
|
||||
simulatorBlocktime: 0 // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining.
|
||||
},
|
||||
privatenet: {
|
||||
enabled: true,
|
||||
networkType: "custom",
|
||||
networkId: "1337",
|
||||
isDev: false,
|
||||
genesisBlock: "config/privatenet/genesis.json", // Genesis block to initiate on first creation of a development node
|
||||
datadir: ".embark/privatenet/datadir",
|
||||
mineWhenNeeded: true,
|
||||
nodiscover: true,
|
||||
maxpeers: 0,
|
||||
rpcHost: "localhost",
|
||||
rpcPort: 8545,
|
||||
rpcCorsDomain: "auto",
|
||||
proxy: true,
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/privatenet/password" // Password to unlock the account
|
||||
}
|
||||
],
|
||||
targetGasLimit: 8000000,
|
||||
wsRPC: true,
|
||||
wsOrigins: "auto",
|
||||
wsHost: "localhost",
|
||||
wsPort: 8546,
|
||||
simulatorBlocktime: 0
|
||||
},
|
||||
testnet: {
|
||||
enabled: true,
|
||||
networkType: "testnet",
|
||||
syncMode: "light",
|
||||
rpcHost: "localhost",
|
||||
rpcPort: 8545,
|
||||
rpcCorsDomain: "http://localhost:8000",
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/testnet/password" // Password to unlock the account
|
||||
}
|
||||
]
|
||||
},
|
||||
livenet: {
|
||||
enabled: true,
|
||||
networkType: "livenet",
|
||||
syncMode: "light",
|
||||
rpcHost: "localhost",
|
||||
rpcPort: 8545,
|
||||
rpcCorsDomain: "http://localhost:8000",
|
||||
accounts: [
|
||||
{
|
||||
nodeAccounts: true,
|
||||
password: "config/livenet/password" // Password to unlock the account
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
module.exports = {
|
||||
default: {
|
||||
enabled: true,
|
||||
provider: "whisper", // Communication provider. Currently, Embark only supports whisper
|
||||
available_providers: ["whisper"], // Array of available providers
|
||||
connection: {
|
||||
host: "localhost", // Host of the blockchain node
|
||||
port: 8546, // Port of the blockchain node
|
||||
type: "ws" // Type of connection (ws or rpc)
|
||||
}
|
||||
}
|
||||
};
|
@ -1,41 +0,0 @@
|
||||
module.exports = {
|
||||
// default applies to all environments
|
||||
default: {
|
||||
// Blockchain node to deploy the contracts
|
||||
deployment: {
|
||||
host: "localhost", // Host of the blockchain node
|
||||
port: 8546, // Port of the blockchain node
|
||||
type: "ws" // Type of connection (ws or rpc),
|
||||
// Accounts to use instead of the default account to populate your wallet
|
||||
/*,accounts: [
|
||||
{
|
||||
privateKey: "your_private_key",
|
||||
balance: "5 ether" // You can set the balance of the account in the dev environment
|
||||
// Balances are in Wei, but you can specify the unit with its name
|
||||
},
|
||||
{
|
||||
privateKeyFile: "path/to/file" // You can put more than one key, separated by , or ;
|
||||
},
|
||||
{
|
||||
mnemonic: "12 word mnemonic",
|
||||
addressIndex: "0", // Optionnal. The index to start getting the address
|
||||
numAddresses: "1", // Optionnal. The number of addresses to get
|
||||
hdpath: "m/44'/60'/0'/0/" // Optionnal. HD derivation path
|
||||
}
|
||||
]*/
|
||||
},
|
||||
// order of connections the dapp should connect to
|
||||
dappConnection: [
|
||||
"$WEB3", // uses pre existing web3 object if available (e.g in Mist)
|
||||
"ws://localhost:8546",
|
||||
"http://localhost:8545"
|
||||
],
|
||||
gas: "auto",
|
||||
contracts: {
|
||||
SimpleStorage: {
|
||||
fromIndex: 0,
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
module.exports = {
|
||||
default: {
|
||||
available_providers: ["ens", "ipns"],
|
||||
provider: "ens",
|
||||
register: {
|
||||
rootDomain: "embark.eth",
|
||||
subdomains: {
|
||||
'status': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"homesteadBlock": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"daoForkSupport": true
|
||||
},
|
||||
"nonce": "0x0000000000000042",
|
||||
"difficulty": "0x0",
|
||||
"alloc": {
|
||||
"0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"}
|
||||
},
|
||||
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0x3333333333333333333333333333333333333333",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x7a1200"
|
||||
}
|
@ -1 +0,0 @@
|
||||
dev_password
|
@ -1,35 +0,0 @@
|
||||
module.exports = {
|
||||
default: {
|
||||
enabled: true,
|
||||
ipfs_bin: "ipfs",
|
||||
available_providers: ["ipfs"],
|
||||
upload: {
|
||||
provider: "ipfs",
|
||||
host: "localhost",
|
||||
port: 5001
|
||||
},
|
||||
dappConnection: [
|
||||
{
|
||||
provider:"ipfs",
|
||||
host: "localhost",
|
||||
port: 5001,
|
||||
getUrl: "http://localhost:8080/ipfs/"
|
||||
}
|
||||
]
|
||||
// Configuration to start Swarm in the same terminal as `embark run`
|
||||
/*,account: {
|
||||
address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm
|
||||
password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account
|
||||
},
|
||||
swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/
|
||||
},
|
||||
development: {
|
||||
enabled: true,
|
||||
upload: {
|
||||
provider: "ipfs",
|
||||
host: "localhost",
|
||||
port: 5001,
|
||||
getUrl: "http://localhost:8080/ipfs/"
|
||||
}
|
||||
}
|
||||
};
|
@ -1 +0,0 @@
|
||||
test_password
|
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
enabled: true,
|
||||
host: "localhost",
|
||||
port: 8000
|
||||
};
|
@ -1,40 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract Branches {
|
||||
uint public lastComparison;
|
||||
uint public storedData;
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
function bigger(uint x) public returns (uint biggest) {
|
||||
lastComparison = x;
|
||||
|
||||
if(x > storedData) {
|
||||
storedData = x;
|
||||
return x;
|
||||
} else {
|
||||
return storedData;
|
||||
}
|
||||
}
|
||||
|
||||
function smaller(uint x) public returns (uint smallest) {
|
||||
lastComparison = x;
|
||||
|
||||
if(x < storedData) {
|
||||
return x;
|
||||
} else {
|
||||
return storedData;
|
||||
}
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
|
||||
function smallFunctionWithoutStatements() public view returns (uint retVal) {
|
||||
if(false) return storedData * 10;
|
||||
if(true) return storedData * 20;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract Events {
|
||||
uint public balance;
|
||||
|
||||
event Deposit(uint value);
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
balance = initialValue;
|
||||
}
|
||||
|
||||
function deposit(uint x) public {
|
||||
balance = balance + x;
|
||||
emit Deposit(x);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract Loops {
|
||||
uint public storedData;
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
|
||||
function set(uint x) public {
|
||||
for(uint i = storedData; i < x; i++) {
|
||||
uint newValue = storedData + x;
|
||||
storedData = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract Modifiers {
|
||||
uint public storedData;
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
modifier upTo(uint amount, uint desired) {
|
||||
require(
|
||||
desired <= amount,
|
||||
"Value is too high."
|
||||
);
|
||||
_;
|
||||
}
|
||||
|
||||
function set(uint x) public upTo(1000, x) {
|
||||
storedData = x;
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
function set(uint x) public {
|
||||
storedData = x;
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
return storedData;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"contracts": ["contracts/**"],
|
||||
"app": {
|
||||
"js/dapp.js": ["app/dapp.js"],
|
||||
"index.html": "app/index.html",
|
||||
"images/": ["app/images/**"]
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"versions": {
|
||||
"web3": "1.0.0-beta",
|
||||
"solc": "0.5.0",
|
||||
"ipfs-api": "17.2.4"
|
||||
},
|
||||
"plugins": {
|
||||
}
|
||||
}
|
278
test_apps/coverage_app/package-lock.json
generated
278
test_apps/coverage_app/package-lock.json
generated
@ -1,278 +0,0 @@
|
||||
{
|
||||
"name": "app_name",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
|
||||
},
|
||||
"babel-runtime": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"requires": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"classnames": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
|
||||
},
|
||||
"core-js": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
|
||||
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
|
||||
},
|
||||
"dom-helpers": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz",
|
||||
"integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg=="
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
|
||||
"requires": {
|
||||
"iconv-lite": "~0.4.13"
|
||||
}
|
||||
},
|
||||
"fbjs": {
|
||||
"version": "0.8.17",
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
|
||||
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
|
||||
"requires": {
|
||||
"core-js": "^1.0.0",
|
||||
"isomorphic-fetch": "^2.1.1",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^0.7.18"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
|
||||
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
},
|
||||
"isomorphic-fetch": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
|
||||
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
|
||||
"requires": {
|
||||
"node-fetch": "^1.0.1",
|
||||
"whatwg-fetch": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"keycode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
|
||||
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
|
||||
"integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.3.1",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"prop-types-extra": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz",
|
||||
"integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==",
|
||||
"requires": {
|
||||
"react-is": "^16.3.2",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.4.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
|
||||
"integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==",
|
||||
"requires": {
|
||||
"fbjs": "^0.8.16",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-bootstrap": {
|
||||
"version": "0.32.1",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.32.1.tgz",
|
||||
"integrity": "sha512-RbfzKUbsukWsToWqGHfCCyMFq9QQI0TznutdyxyJw6dih2NvIne25Mrssg8LZsprqtPpyQi8bN0L0Fx3fUsL8Q==",
|
||||
"requires": {
|
||||
"babel-runtime": "^6.11.6",
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.0",
|
||||
"invariant": "^2.2.1",
|
||||
"keycode": "^2.1.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-overlays": "^0.8.0",
|
||||
"react-prop-types": "^0.4.0",
|
||||
"react-transition-group": "^2.0.0",
|
||||
"uncontrollable": "^4.1.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.4.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz",
|
||||
"integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==",
|
||||
"requires": {
|
||||
"fbjs": "^0.8.16",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.4.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.4.2.tgz",
|
||||
"integrity": "sha512-rI3cGFj/obHbBz156PvErrS5xc6f1eWyTwyV4mo0vF2lGgXgS+mm7EKD5buLJq6jNgIagQescGSVG2YzgXt8Yg=="
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-overlays": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.8.3.tgz",
|
||||
"integrity": "sha512-h6GT3jgy90PgctleP39Yu3eK1v9vaJAW73GOA/UbN9dJ7aAN4BTZD6793eI1D5U+ukMk17qiqN/wl3diK1Z5LA==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"dom-helpers": "^3.2.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"prop-types-extra": "^1.0.1",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-prop-types": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
|
||||
"integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=",
|
||||
"requires": {
|
||||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz",
|
||||
"integrity": "sha512-Xv5d55NkJUxUzLCImGSanK8Cl/30sgpOEMGc5m86t8+kZwrPxPCPcFqyx83kkr+5Lz5gs6djuvE5By+gce+VjA==",
|
||||
"requires": {
|
||||
"dom-helpers": "^3.3.1",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.18",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
|
||||
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
|
||||
},
|
||||
"uncontrollable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-4.1.0.tgz",
|
||||
"integrity": "sha1-4DWCkSUuGGUiLZCTmxny9J+Bwak=",
|
||||
"requires": {
|
||||
"invariant": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
|
||||
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "coverage_app",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "Gruntfile.js",
|
||||
"scripts": {
|
||||
"coverage": "istanbul report --root .embark --format html",
|
||||
"embark": "node ../../bin/embark",
|
||||
"test": "npm run embark test"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"homepage": "",
|
||||
"dependencies": {
|
||||
"react": "^16.3.2",
|
||||
"react-bootstrap": "^0.32.1",
|
||||
"react-dom": "^16.3.2",
|
||||
"istanbul": "^0.4.5"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const Branches = require('Embark/contracts/Branches');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"Branches": {
|
||||
args: [5]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("Branches", function() {
|
||||
it("should return the bigger value and set it", function(done) {
|
||||
Branches.methods.bigger(10).send().then(() => {
|
||||
Branches.methods.get().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 10);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should return the set number if it's bigger", function(done) {
|
||||
Branches.methods.bigger(1).send().then(() => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should return the smaller number", function(done) {
|
||||
Branches.methods.smaller(10).send().then(() => { done(); });
|
||||
});
|
||||
|
||||
it("should not crash code coverage on `if` without statements", function(done) {
|
||||
Branches.methods.smallFunctionWithoutStatements().call().then(() => { done(); });
|
||||
});
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const Events = require('Embark/contracts/Events');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"Events": {
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("Events", function() {
|
||||
it("should deposit", function(done) {
|
||||
Events.methods.deposit(10).send().then(() => { done(); });
|
||||
});
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const Loops = require('Embark/contracts/Loops');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"Loops": {
|
||||
args: [1]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("Loops", function() {
|
||||
it("should set constructor value", function(done) {
|
||||
Loops.methods.storedData().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("set storage value", function(done) {
|
||||
Loops.methods.set(5).send().then(() => {
|
||||
Loops.methods.get().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 21);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const Modifiers = require('Embark/contracts/Modifiers');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"Modifiers": {
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("Modifiers", function() {
|
||||
it("should set constructor value", function(done) {
|
||||
Modifiers.methods.storedData().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 100);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("set storage value when valid", function(done) {
|
||||
Modifiers.methods.set(150).send().then(() => {
|
||||
Modifiers.methods.get().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 150);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("refuses storage value when invalid", function(done) {
|
||||
Modifiers.methods.set(10000).send().catch((_err) => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
/*global contract, config, it, assert*/
|
||||
const SimpleStorage = require('Embark/contracts/SimpleStorage');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"SimpleStorage": {
|
||||
args: [100]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("SimpleStorage", function() {
|
||||
it("should set constructor value", function(done) {
|
||||
SimpleStorage.methods.storedData().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 100);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("set storage value", function(done) {
|
||||
SimpleStorage.methods.set(150).send().then(() => {
|
||||
SimpleStorage.methods.get().call().then((result) => {
|
||||
assert.strictEqual(parseInt(result, 10), 150);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user