embark/lib/contracts/blockchain.js

222 lines
6.1 KiB
JavaScript
Raw Normal View History

2018-05-18 21:15:49 +00:00
const Web3 = require('web3');
const async = require('async');
2018-05-18 18:58:05 +00:00
const Provider = require('./provider.js');
2018-05-22 21:34:54 +00:00
const request = require('request');
2018-05-18 20:51:03 +00:00
class Blockchain {
2018-05-18 21:15:49 +00:00
constructor(options) {
2018-05-18 20:51:03 +00:00
this.plugins = options.plugins;
this.logger = options.logger;
2018-05-18 22:31:47 +00:00
this.events = options.events;
this.contractsConfig = options.contractsConfig;
this.blockchainConfig = options.blockchainConfig;
2018-05-18 21:15:49 +00:00
this.web3 = options.web3;
2018-05-18 22:31:47 +00:00
this.addCheck = options.addCheck;
2018-05-18 21:15:49 +00:00
2018-05-18 18:58:05 +00:00
this.isWeb3Started = false;
2018-05-18 21:15:49 +00:00
if (!this.web3) {
this.initWeb3();
}
this.registerServiceCheck();
this.registerRequests();
2018-05-23 15:16:56 +00:00
this.registerWeb3Object();
2018-05-18 21:15:49 +00:00
}
2018-05-22 21:34:54 +00:00
initWeb3(cb) {
2018-05-18 18:58:05 +00:00
const self = this;
2018-05-18 21:15:49 +00:00
this.web3 = new Web3();
if (this.contractsConfig.deployment.type === "rpc") {
2018-05-18 18:58:05 +00:00
let provider;
2018-05-22 21:34:54 +00:00
self.web3Endpoint = 'http://' + this.contractsConfig.deployment.host + ':' + this.contractsConfig.deployment.port;
2018-05-18 18:58:05 +00:00
const providerOptions = {
web3: this.web3,
accountsConfig: this.contractsConfig.deployment.accounts,
logger: this.logger,
isDev: this.isDev,
2018-05-22 21:34:54 +00:00
web3Endpoint: self.web3Endpoint
2018-05-18 18:58:05 +00:00
};
provider = new Provider(providerOptions);
provider.startWeb3Provider(() => {
self.isWeb3Started = true;
2018-05-22 21:34:54 +00:00
if (cb) {
cb();
}
2018-05-18 18:58:05 +00:00
});
2018-05-18 21:15:49 +00:00
} else {
throw new Error("contracts config error: unknown deployment type " + this.contractsConfig.deployment.type);
}
}
registerServiceCheck() {
const self = this;
this.addCheck('Ethereum', function (cb) {
async.waterfall([
function checkNodeConnection(next) {
self.assertNodeConnection(true, (err) => {
if (err) {
return next(null, {name: "No Blockchain node found", status: 'off'});
}
next();
});
},
function checkVersion(next) {
// TODO: web3_clientVersion method is currently not implemented in web3.js 1.0
self.web3._requestManager.send({method: 'web3_clientVersion', params: []}, (err, version) => {
if (err) {
return next(null, {name: "Ethereum node (version unknown)", status: 'on'});
}
if (version.indexOf("/") < 0) {
return next(null, {name: version, status: 'on'});
}
let nodeName = version.split("/")[0];
let versionNumber = version.split("/")[1].split("-")[0];
let name = nodeName + " " + versionNumber + " (Ethereum)";
return next(null, {name: name, status: 'on'});
});
}
], (err, statusObj) => {
2018-05-18 21:15:49 +00:00
if (err) {
self.logger.error(err);
return;
2018-05-18 21:15:49 +00:00
}
cb(statusObj);
2018-05-18 21:15:49 +00:00
});
});
2018-05-18 20:51:03 +00:00
}
2018-05-18 21:15:49 +00:00
registerRequests() {
2018-05-18 22:31:47 +00:00
const self = this;
this.events.setCommandHandler("blockchain:defaultAccount:get", function(cb) {
cb(self.defaultAccount);
});
this.events.setCommandHandler("blockchain:defaultAccount:set", function(account, cb) {
self.setDefaultAccount(account);
cb();
});
this.events.setCommandHandler("blockchain:block:byNumber", function(blockNumber, cb) {
self.getBlock(blockNumber, cb);
});
2018-05-18 22:31:47 +00:00
}
defaultAccount() {
return this.web3.eth.defaultAccount;
}
setDefaultAccount(account) {
this.web3.eth.defaultAccount = account;
}
getAccounts(cb) {
this.web3.eth.getAccounts(cb);
}
2018-05-18 22:41:04 +00:00
getCode(address, cb) {
this.web3.eth.getCode(address, cb);
}
2018-05-18 22:50:20 +00:00
getBlock(blockNumber, cb) {
this.web3.eth.getBlock(blockNumber, cb);
}
ContractObject(params) {
return new this.web3.eth.Contract(params.abi);
}
2018-05-19 00:26:21 +00:00
deployContractObject(contractObject, params) {
return contractObject.deploy({arguments: params.arguments, data: params.data});
}
estimateDeployContractGas(deployObject, cb) {
return deployObject.estimateGas().then((gasValue) => {
cb(null, gasValue);
}).catch(cb);
}
deployContractFromObject(deployContractObject, params, cb) {
deployContractObject.send({
from: params.from, gas: params.gas, gasPrice: params.gasPrice
}).on('receipt', function(receipt) {
if (receipt.contractAddress !== undefined) {
cb(null, receipt);
}
}).on('error', cb);
}
assertNodeConnection(noLogs, cb) {
if (typeof noLogs === 'function') {
cb = noLogs;
noLogs = false;
}
const NO_NODE_ERROR = Error("error connecting to blockchain node");
const self = this;
async.waterfall([
function checkInstance(next) {
if (!self.web3) {
return next(Error("no web3 instance found"));
}
next();
},
function checkProvider(next) {
if (self.web3.currentProvider === undefined) {
return next(NO_NODE_ERROR);
}
next();
},
function pingEndpoint(next) {
request.get(self.web3Endpoint, function (err, _response, _body) {
if (err) {
return next(NO_NODE_ERROR);
}
next();
});
},
function checkAccounts(next) {
self.getAccounts(function(err, _accounts) {
if (err) {
return next(NO_NODE_ERROR);
}
return next();
});
}
], function (err) {
if (!noLogs && err === NO_NODE_ERROR) {
self.logger.error(("Couldn't connect to an Ethereum node are you sure it's on?").red);
self.logger.info("make sure you have an Ethereum node or simulator running. e.g 'embark blockchain'".magenta);
}
cb(err);
});
}
determineDefaultAccount(cb) {
const self = this;
self.getAccounts(function (err, accounts) {
if (err) {
self.logger.error(err);
return cb(new Error(err));
}
let accountConfig = self.blockchainConfig.account;
let selectedAccount = accountConfig && accountConfig.address;
self.setDefaultAccount(selectedAccount || accounts[0]);
cb();
});
}
2018-05-23 15:16:56 +00:00
registerWeb3Object() {
// doesn't feel quite right, should be a cmd or plugin method
// can just be a command without a callback
this.events.emit("runcode:register", "web3", this.web3);
}
2018-05-18 20:51:03 +00:00
}
module.exports = Blockchain;