UNPKG

scryinfo

Version:

A real data storage library on ethereum

292 lines (263 loc) 10.9 kB
/** en: normalized struct data for callback: zh: callback或事件回调的参数, 是统一的格式: { st: ScryStatus.xx, // @see{ScryStatus} msg: "", // error message. 错误或提示信息. error: error object, // error object. 错误时,返回的error对象. data: object // the business object. 返回的一些具体结果对象. } @author Danny Yan @date 2017-08 */ var path = require("path"); var fs = require("fs"); var Web3 = require("web3"); var util = require('util'); var events = require('events'); var base58 = require('base-58'); // npm install base-58 var concat = require('concat-stream'); var keythereum = require("keythereum"); var Tx = require('ethereumjs-tx'); var Status = require("./scryStatus.js"); /** constructor */ function Scry(providerURL) { var web3 = this.web3 = new Web3(); this.eth = web3.eth; this.personal = web3.personal; this.admin = web3.admin; this.providerURL = providerURL; this._accountsDirty = true; this.accounts = this.getAccounts(); } util.inherits(Scry, events.EventEmitter); /** en: Start scry system. zh: 开始启动 @param callback function. */ Scry.prototype.start = function(callback) { this.web3.setProvider(new Web3.providers.HttpProvider(this.providerURL, 0)); var isOK = this.web3.isConnected(); // 这里是同步阻塞 console.log("scry start successfully."); callback(isOK); }; /** en: Get all accounts from keystore directory. zh: 从keystore目录获取所有账号信息 @param strict boolean. If strict is true, will throw error when results are empty. Default value is false @retrun Array<Ojbect>. Return a array. */ Scry.prototype.getAccounts = function(strict) { if (this._accountsDirty == false) { if (strict && this.accounts.length < 1) { throw new Error("accounts is empty."); } return this.accounts; } var dir = path.resolve(__dirname + "/keystore/"); if (fs.existsSync(dir) == false) { fs.mkdir(dir); } console.log(); // ? install by npm, it will be wrong on first run!! var files = fs.readdirSync(dir); var list = []; for (var i = 0, len = files.length; i < len; i++) { var data = fs.readFileSync(dir + "\\" + files[i]); var keyObject = JSON.parse(data.toString()); list.push("0x" + keyObject.address); } this._accountsDirty = false; this.accounts = list; if (strict && list.length < 1) { throw new Error("accounts is empty."); } return list; }; /** en: Get eth balance. zh: 获取eth余额. @param from string. account address. @param toWei boolean. Default value is true */ Scry.prototype.getBalance = function(from, toWei) { if (toWei == null) toWei = true; var val = this.eth.getBalance(from).toNumber(); return toWei ? val : this.web3.fromWei(val); }; /** en: Get a instance of contract by address and abi. zh: 通过地址和abi获取一个合约实例 @param address string. @param abi string. @return object. */ Scry.prototype.getContractInstance = function(address, abi) { if (typeof(address) != "string" || typeof(abi) != "string") { throw new Error("address or abi is null."); } var abiObj = typeof(abi) == "string" ? JSON.parse(abi) : abi; var _contract = this.eth.contract(abiObj); var _contractInst = _contract.at(address); return _contractInst; }; /** en: watch event zh: 监听事件 @param eventFunc object. web3 function object. @param txHash string. 如果指定此值,则只有事件返回的transactionHash与其相等时才会触发回调 @param callback function. */ Scry.prototype.watchEvent = function(eventFunc, txHash, callback) { if (eventFunc == null || typeof(eventFunc) != "function") { throw new Error("eventFunc must be a function type."); return; } var myEvent = eventFunc(); myEvent.watch(function(err, result) { if (err == null) { if (txHash == null) { typeof(callback) == "function" && callback(Status.returnOK( result )); } else if (result.transactionHash == txHash) { typeof(callback) == "function" && callback(Status.returnOK( result )); } // console.log("myEvent:",result); } else { // console.log("myEvent err: ", err); typeof(callback) == "function" && callback(Status.returnError( err.toString(), err )); } myEvent.stopWatching(); }); }; /** en: Get the address logs. zh: 获取一个指定地址上的日志(事件结果).但不包含事件的详细信息(合约中的事件参数) @param address string. @param fromBlock number|string. Start block number. Default value is 'latest'. 指定的起始区块号. 可不填,默认为"latest" @param toBlock number|string. End block number. Default value is 'latest'. 指定的结束区块号. 可不填,默认为"latest" @param callback function. */ Scry.prototype.getLogs = function(address, fromBlock, toBlock, callback) { var filter = this.eth.filter({ address: address, fromBlock: fromBlock || "latest", toBlock: toBlock || 'latest' }); var myResults = filter.get(function(err, rs) { if (err != null) { typeof(callback) == "function" && callback(Status.returnError( err.toString(), err )); return; } typeof(callback) == "function" && callback(Status.returnOK( rs )); }); }; /** en: Get contract's all events. zh: 获取一个合约的所有日志. 包含事件的详细信息. @param contractInst object. contract object. @param fromBlock number|string. Start block number. Default value is 'latest'. 指定的起始区块号. 可不填,默认为"latest" @param toBlock number|string. End block number. Default value is 'latest'. 指定的结束区块号. 可不填,默认为"latest" @param callback function. */ Scry.prototype.getEvents = function(contractInst, fromBlock, toBlock, callback) { var events = null; events = contractInst.allEvents({ address: contractInst.address, fromBlock: fromBlock || "latest", toBlock: toBlock || 'latest' }, function(err, rs) { if (err != null) { typeof(callback) == "function" && callback(Status.returnError( err.toString(), err )); return; } typeof(callback) == "function" && callback(Status.returnOK( rs )); events.stopWatching(); }); }; /** en: Read contents from file zh: 从指定路径的文件中读取内容 @param p string. File path */ Scry.prototype.loadContentFromFile = function(p) { p = path.resolve(p); if (fs.existsSync(p) == false) return null; var cnt = fs.readFileSync(p); return cnt.toString(); }; /** en: Call contract's function, use 'call'. It won't produce a transaction. zh: 调用合约的非交易方法(同call). 一定会处理为指定一个from, 默认的from是accoutns[0] @param options object. 格式为: { address:"", // Contract address. Don't have to fill in when set 'func'. 合约地址. func指定时,可不填 abi:"", // Contract abi code. Don't have to fill in when set 'func'. 合约abi. func指定时,可不填 funcName:"", // Contract function name. Don't have to fill in when set 'func'. 调用的合约方法名. func指定时,可不填 func: ojbect, // Contract function object. If you set this value, the aforementioned three values will invalid. contract的function对象,如果存在此值,则不用填写上述3个值 from:"", // Caller address. Default value is accounts[0]. 可不填, 默认accounts[0] params:[] // The contract function's parameters array. 调用方法所需的参数. 可不填 } @return */ Scry.prototype.contractCall = function(options) { if (options == null) { throw new Error("invalid options parameters."); } var func = options.func; if (func == null) { var address = options.address; var abi = options.abi; var funcName = options.funcName; if (address == null || abi == null || funcName == null) { throw new Error("invalid options parameters."); } var inst = this.getContractInstance(address, abi); if (inst == null) { throw new Error("contract is null."); } func = inst[funcName]; if (func == null) { throw new Error("contract function '" + funcName + "' is null."); } } params = options.params; if (params != null && !(params instanceof Array)) { throw new Error("params must be an instance of Array."); } params = params || []; // 调用合约非交易方法时,必须指定from为当前账号,否则默认使用远程代理节点的账号 var from = options.from || this.getAccounts(true)[0]; params.push({ from: from }); return func.call.apply(func, params); }; /** en: Get contract function's data for payload. zh: 生成执行合约方法所需的payloadData @param object. Contract function object. 合约的方法对象 @param params Array. The contract function's parameters array. 合约方法所需的参数数组 */ Scry.prototype.getPayloadData = function(funcObj, params) { if (params != null && !(params instanceof Array)) { throw new Error("deployed fail: options.params must be an instance of Arry."); } var payloadData = funcObj.getData.apply(funcObj, params); return payloadData; }; /** en: Verify address's password is correct. zh: 验证密码是否正确 @param address string. @param password string. @param callback function. */ Scry.prototype.verifyPass = function(address, password, callback) { if (address == null || password == null) { throw new Error("invalid parameters."); } var keyObject = keythereum.importFromFile(address, __dirname); if (keyObject == null) { typeof(callback) == "function" && callback(Status.returnError("account '" + address + "'s privatekey is not exist." )); return; } var privateKey = keythereum.recover(password, keyObject); if (privateKey == null) { typeof(callback) == "function" && callback(Status.returnError("the address and password is mismatching." )); } else { typeof(callback) == "function" && callback(Status.returnOK("verify correctly.")); } }; module.exports = Scry;