feat: add coverage events

Instead of looking at the transaction, instrument the
source to publish coverage event
This commit is contained in:
Anthony Laibe 2018-12-04 09:27:13 +00:00 committed by Iuri Matias
parent 7574e141fa
commit 8a6d075cd1
56 changed files with 2542 additions and 2528 deletions

View File

@ -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",

View File

@ -56,7 +56,8 @@
"restart": "restart"
},
"tests": {
"gasLimit": 6000000
"gasLimit": 6000000,
"coverageGasLimit": 4503599627370495
},
"codeGenerator": {
"gasLimit": 6000000

View File

@ -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,

View File

@ -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',

View 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);
}
}

View File

@ -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;

View File

@ -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;

View 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};
}

View File

@ -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;

View 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);
}
}

View 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");
}
}

View 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);
},
});
}
}

View 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});
}
}

View File

@ -0,0 +1,5 @@
import * as path from "path";
const fs = require("../../core/fs");
export const coverageContractsPath = () => path.join(fs.dappPath(), "coverage", "instrumentedContracts");

View File

@ -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;

View 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, "");
}
}

View 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;
};
}

View File

@ -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, '');
}

View File

@ -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);

View 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) {

View File

@ -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();
});
});
});

View File

@ -2,5 +2,6 @@ import { ABIDefinition } from "web3/eth/abi";
export interface Contract {
abiDefinition: ABIDefinition[];
deployedAddress: string;
className: string;
}

View File

@ -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;
}

View 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;
}

View File

@ -15,4 +15,4 @@ contract SimpleStorage {
return storedData;
}
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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'));

View File

@ -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>

View File

@ -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
}
]
}
};

View File

@ -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)
}
}
};

View File

@ -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]
}
}
}
};

View File

@ -1,12 +0,0 @@
module.exports = {
default: {
available_providers: ["ens", "ipns"],
provider: "ens",
register: {
rootDomain: "embark.eth",
subdomains: {
'status': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
}
}
}
};

View File

@ -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"
}

View File

@ -1 +0,0 @@
dev_password

View File

@ -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/"
}
}
};

View File

@ -1 +0,0 @@
test_password

View File

@ -1,5 +0,0 @@
module.exports = {
enabled: true,
host: "localhost",
port: 8000
};

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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": {
}
}

View File

@ -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=="
}
}
}

View File

@ -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"
}
}

View File

@ -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(); });
});
});

View File

@ -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(); });
});
});

View File

@ -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();
});
});
});
});

View File

@ -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();
});
});
});

View File

@ -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();
});
});
});
});

1703
yarn.lock

File diff suppressed because it is too large Load Diff