Merge commit '1a6dbeff6e86d65cae6d7db366cbaa4182eaff7f' into ethereumjs
Conflicts: libjsqrc/ethereumjs/dist/ethereum.js libjsqrc/ethereumjs/dist/ethereum.js.map libjsqrc/ethereumjs/dist/ethereum.min.js libjsqrc/ethereumjs/lib/abi.js
This commit is contained in:
commit
6d02c0d392
|
@ -66,16 +66,16 @@ sudo apt-get install npm
|
||||||
sudo apt-get install nodejs-legacy
|
sudo apt-get install nodejs-legacy
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
### Building (gulp)
|
||||||
|
|
||||||
```bash (gulp)
|
```bash
|
||||||
npm run-script build
|
npm run-script build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Testing
|
### Testing (mocha)
|
||||||
|
|
||||||
```bash (mocha)
|
```bash
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
// create contract
|
// create contract
|
||||||
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
|
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
|
||||||
contract = web3.contract(address, desc);
|
contract = web3.eth.contract(address, desc);
|
||||||
document.getElementById('call').style.visibility = 'visible';
|
document.getElementById('call').style.visibility = 'visible';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
2
index.js
2
index.js
|
@ -3,6 +3,6 @@ web3.providers.WebSocketProvider = require('./lib/websocket');
|
||||||
web3.providers.HttpRpcProvider = require('./lib/httprpc');
|
web3.providers.HttpRpcProvider = require('./lib/httprpc');
|
||||||
web3.providers.QtProvider = require('./lib/qt');
|
web3.providers.QtProvider = require('./lib/qt');
|
||||||
web3.providers.AutoProvider = require('./lib/autoprovider');
|
web3.providers.AutoProvider = require('./lib/autoprovider');
|
||||||
web3.contract = require('./lib/contract');
|
web3.eth.contract = require('./lib/contract');
|
||||||
|
|
||||||
module.exports = web3;
|
module.exports = web3;
|
||||||
|
|
227
lib/abi.js
227
lib/abi.js
|
@ -35,6 +35,10 @@ var decToHex = function (dec) {
|
||||||
return parseInt(dec).toString(16);
|
return parseInt(dec).toString(16);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Finds first index of array element matching pattern
|
||||||
|
/// @param array
|
||||||
|
/// @param callback pattern
|
||||||
|
/// @returns index of element
|
||||||
var findIndex = function (array, callback) {
|
var findIndex = function (array, callback) {
|
||||||
var end = false;
|
var end = false;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
@ -44,106 +48,96 @@ var findIndex = function (array, callback) {
|
||||||
return end ? i - 1 : -1;
|
return end ? i - 1 : -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns a function that is used as a pattern for 'findIndex'
|
||||||
var findMethodIndex = function (json, methodName) {
|
var findMethodIndex = function (json, methodName) {
|
||||||
return findIndex(json, function (method) {
|
return findIndex(json, function (method) {
|
||||||
return method.name === methodName;
|
return method.name === methodName;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var padLeft = function (string, chars) {
|
/// @param string string to be padded
|
||||||
return new Array(chars - string.length + 1).join("0") + string;
|
/// @param number of characters that result string should have
|
||||||
|
/// @param sign, by default 0
|
||||||
|
/// @returns right aligned string
|
||||||
|
var padLeft = function (string, chars, sign) {
|
||||||
|
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
|
||||||
};
|
};
|
||||||
|
|
||||||
var calcBitPadding = function (type, expected) {
|
/// @param expected type prefix (string)
|
||||||
var value = type.slice(expected.length);
|
/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
|
||||||
if (value === "") {
|
var prefixedType = function (prefix) {
|
||||||
return 32;
|
return function (type) {
|
||||||
}
|
return type.indexOf(prefix) === 0;
|
||||||
return parseInt(value) / 8;
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var calcBytePadding = function (type, expected) {
|
/// @param expected type name (string)
|
||||||
var value = type.slice(expected.length);
|
/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
|
||||||
if (value === "") {
|
var namedType = function (name) {
|
||||||
return 32;
|
return function (type) {
|
||||||
}
|
return name === type;
|
||||||
return parseInt(value);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
var calcRealPadding = function (type, expected) {
|
|
||||||
var value = type.slice(expected.length);
|
|
||||||
if (value === "") {
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
var sizes = value.split('x');
|
|
||||||
for (var padding = 0, i = 0; i < sizes; i++) {
|
|
||||||
padding += (sizes[i] / 8);
|
|
||||||
}
|
|
||||||
return padding;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Setups input formatters for solidity types
|
||||||
|
/// @returns an array of input formatters
|
||||||
var setupInputTypes = function () {
|
var setupInputTypes = function () {
|
||||||
|
|
||||||
// convert from int, decimal-string, prefixed hex string whatever into a bare hex string.
|
/// Formats input value to byte representation of int
|
||||||
var formatStandard = function (value) {
|
/// @returns right-aligned byte representation of int
|
||||||
if (typeof value === "number")
|
var formatInt = function (value) {
|
||||||
return value.toString(16);
|
var padding = 32 * 2;
|
||||||
else if (typeof value === "string" && value.indexOf('0x') === 0)
|
if (typeof value === 'number') {
|
||||||
return value.substr(2);
|
if (value < 0) {
|
||||||
else if (typeof value === "string")
|
|
||||||
return web3.toHex(value);
|
// two's complement
|
||||||
|
// TODO: fix big numbers support
|
||||||
|
value = ((value) >>> 0).toString(16);
|
||||||
|
return padLeft(value, padding, 'f');
|
||||||
|
}
|
||||||
|
value = value.toString(16);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (value.indexOf('0x') === 0)
|
||||||
|
value = value.substr(2);
|
||||||
|
else if (typeof value === 'string')
|
||||||
|
value = value.toHex(value);
|
||||||
else
|
else
|
||||||
return (+value).toString(16);
|
value = (+value).toString(16);
|
||||||
|
return padLeft(value, padding);
|
||||||
};
|
};
|
||||||
|
|
||||||
var prefixedType = function (prefix, calcPadding) {
|
/// Formats input value to byte representation of string
|
||||||
return function (type, value) {
|
/// @returns left-algined byte representation of string
|
||||||
var expected = prefix;
|
var formatString = function (value) {
|
||||||
if (type.indexOf(expected) !== 0) {
|
return web3.fromAscii(value, 32).substr(2);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var padding = calcPadding(type, expected);
|
|
||||||
if (padding > 32)
|
|
||||||
return false; // not allowed to be so big.
|
|
||||||
padding = 32; // override as per the new ABI.
|
|
||||||
|
|
||||||
if (prefix === "string")
|
|
||||||
return web3.fromAscii(value, padding).substr(2);
|
|
||||||
return padLeft(formatStandard(value), padding * 2);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var namedType = function (name, padding, formatter) {
|
|
||||||
return function (type, value) {
|
|
||||||
if (type !== name) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
padding = 32; //override as per the new ABI.
|
|
||||||
|
|
||||||
return padLeft(formatter ? formatter(value) : value, padding * 2);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Formats input value to byte representation of bool
|
||||||
|
/// @returns right-aligned byte representation bool
|
||||||
var formatBool = function (value) {
|
var formatBool = function (value) {
|
||||||
return value ? '01' : '00';
|
return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
prefixedType('uint', calcBitPadding),
|
{ type: prefixedType('uint'), format: formatInt },
|
||||||
prefixedType('int', calcBitPadding),
|
{ type: prefixedType('int'), format: formatInt },
|
||||||
prefixedType('hash', calcBitPadding),
|
{ type: prefixedType('hash'), format: formatInt },
|
||||||
prefixedType('string', calcBytePadding),
|
{ type: prefixedType('string'), format: formatString },
|
||||||
prefixedType('real', calcRealPadding),
|
{ type: prefixedType('real'), format: formatInt },
|
||||||
prefixedType('ureal', calcRealPadding),
|
{ type: prefixedType('ureal'), format: formatInt },
|
||||||
namedType('address', 20, formatStandard),
|
{ type: namedType('address'), format: formatInt },
|
||||||
namedType('bool', 1, formatBool),
|
{ type: namedType('bool'), format: formatBool }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
var inputTypes = setupInputTypes();
|
var inputTypes = setupInputTypes();
|
||||||
|
|
||||||
|
/// Formats input params to bytes
|
||||||
|
/// @param contract json abi
|
||||||
|
/// @param name of the method that we want to use
|
||||||
|
/// @param array of params that will be formatted to bytes
|
||||||
|
/// @returns bytes representation of input params
|
||||||
var toAbiInput = function (json, methodName, params) {
|
var toAbiInput = function (json, methodName, params) {
|
||||||
var bytes = "";
|
var bytes = "";
|
||||||
var index = findMethodIndex(json, methodName);
|
var index = findMethodIndex(json, methodName);
|
||||||
|
@ -153,74 +147,72 @@ var toAbiInput = function (json, methodName, params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var method = json[index];
|
var method = json[index];
|
||||||
|
var padding = 32 * 2;
|
||||||
|
|
||||||
for (var i = 0; i < method.inputs.length; i++) {
|
for (var i = 0; i < method.inputs.length; i++) {
|
||||||
var found = false;
|
var typeMatch = false;
|
||||||
for (var j = 0; j < inputTypes.length && !found; j++) {
|
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
|
||||||
found = inputTypes[j](method.inputs[i].type, params[i]);
|
typeMatch = inputTypes[j].type(method.inputs[i].type, params[i]);
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!typeMatch) {
|
||||||
console.error('unsupported json type: ' + method.inputs[i].type);
|
console.error('input parser does not support type: ' + method.inputs[i].type);
|
||||||
}
|
}
|
||||||
bytes += found;
|
|
||||||
|
var formatter = inputTypes[j - 1].format;
|
||||||
|
bytes += (formatter ? formatter(params[i]) : params[i]);
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Setups output formaters for solidity types
|
||||||
|
/// @returns an array of output formatters
|
||||||
var setupOutputTypes = function () {
|
var setupOutputTypes = function () {
|
||||||
|
|
||||||
var prefixedType = function (prefix, calcPadding) {
|
/// Formats input right-aligned input bytes to int
|
||||||
return function (type) {
|
/// @returns right-aligned input bytes formatted to int
|
||||||
var expected = prefix;
|
|
||||||
if (type.indexOf(expected) !== 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var padding = calcPadding(type, expected);
|
|
||||||
if (padding > 32)
|
|
||||||
return -1; // not allowed to be so big.
|
|
||||||
padding = 32; // override as per the new ABI.
|
|
||||||
return padding * 2;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var namedType = function (name, padding) {
|
|
||||||
return function (type) {
|
|
||||||
padding = 32; // override as per the new ABI.
|
|
||||||
return name === type ? padding * 2 : -1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var formatInt = function (value) {
|
var formatInt = function (value) {
|
||||||
return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
|
return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns right-aligned input bytes formatted to hex
|
||||||
var formatHash = function (value) {
|
var formatHash = function (value) {
|
||||||
return "0x" + value;
|
return "0x" + value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns right-aligned input bytes formatted to bool
|
||||||
var formatBool = function (value) {
|
var formatBool = function (value) {
|
||||||
return value === '1' ? true : false;
|
return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns left-aligned input bytes formatted to ascii string
|
||||||
var formatString = function (value) {
|
var formatString = function (value) {
|
||||||
return web3.toAscii(value);
|
return web3.toAscii(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns right-aligned input bytes formatted to address
|
||||||
|
var formatAddress = function (value) {
|
||||||
|
return "0x" + value.slice(value.length - 40, value.length);
|
||||||
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ padding: prefixedType('uint', calcBitPadding), format: formatInt },
|
{ type: prefixedType('uint'), format: formatInt },
|
||||||
{ padding: prefixedType('int', calcBitPadding), format: formatInt },
|
{ type: prefixedType('int'), format: formatInt },
|
||||||
{ padding: prefixedType('hash', calcBitPadding), format: formatHash },
|
{ type: prefixedType('hash'), format: formatHash },
|
||||||
{ padding: prefixedType('string', calcBytePadding), format: formatString },
|
{ type: prefixedType('string'), format: formatString },
|
||||||
{ padding: prefixedType('real', calcRealPadding), format: formatInt },
|
{ type: prefixedType('real'), format: formatInt },
|
||||||
{ padding: prefixedType('ureal', calcRealPadding), format: formatInt },
|
{ type: prefixedType('ureal'), format: formatInt },
|
||||||
{ padding: namedType('address', 20) },
|
{ type: namedType('address'), format: formatAddress },
|
||||||
{ padding: namedType('bool', 1), format: formatBool }
|
{ type: namedType('bool'), format: formatBool }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
var outputTypes = setupOutputTypes();
|
var outputTypes = setupOutputTypes();
|
||||||
|
|
||||||
|
/// Formats output bytes back to param list
|
||||||
|
/// @param contract json abi
|
||||||
|
/// @param name of the method that we want to use
|
||||||
|
/// @param bytes representtion of output
|
||||||
|
/// @returns array of output params
|
||||||
var fromAbiOutput = function (json, methodName, output) {
|
var fromAbiOutput = function (json, methodName, output) {
|
||||||
var index = findMethodIndex(json, methodName);
|
var index = findMethodIndex(json, methodName);
|
||||||
|
|
||||||
|
@ -232,14 +224,16 @@ var fromAbiOutput = function (json, methodName, output) {
|
||||||
|
|
||||||
var result = [];
|
var result = [];
|
||||||
var method = json[index];
|
var method = json[index];
|
||||||
|
var padding = 32 * 2;
|
||||||
for (var i = 0; i < method.outputs.length; i++) {
|
for (var i = 0; i < method.outputs.length; i++) {
|
||||||
var padding = -1;
|
var typeMatch = false;
|
||||||
for (var j = 0; j < outputTypes.length && padding === -1; j++) {
|
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
|
||||||
padding = outputTypes[j].padding(method.outputs[i].type);
|
typeMatch = outputTypes[j].type(method.outputs[i].type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (padding === -1) {
|
if (!typeMatch) {
|
||||||
// not found output parsing
|
// not found output parsing
|
||||||
|
console.error('output parser does not support type: ' + method.outputs[i].type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var res = output.slice(0, padding);
|
var res = output.slice(0, padding);
|
||||||
|
@ -251,6 +245,8 @@ var fromAbiOutput = function (json, methodName, output) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @param json abi for contract
|
||||||
|
/// @returns input parser object for given json abi
|
||||||
var inputParser = function (json) {
|
var inputParser = function (json) {
|
||||||
var parser = {};
|
var parser = {};
|
||||||
json.forEach(function (method) {
|
json.forEach(function (method) {
|
||||||
|
@ -263,6 +259,8 @@ var inputParser = function (json) {
|
||||||
return parser;
|
return parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @param json abi for contract
|
||||||
|
/// @returns output parser for given json abi
|
||||||
var outputParser = function (json) {
|
var outputParser = function (json) {
|
||||||
var parser = {};
|
var parser = {};
|
||||||
json.forEach(function (method) {
|
json.forEach(function (method) {
|
||||||
|
@ -274,6 +272,9 @@ var outputParser = function (json) {
|
||||||
return parser;
|
return parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @param json abi for contract
|
||||||
|
/// @param method name for which we want to get method signature
|
||||||
|
/// @returns (promise) contract method signature for method with given name
|
||||||
var methodSignature = function (json, name) {
|
var methodSignature = function (json, name) {
|
||||||
var method = json[findMethodIndex(json, name)];
|
var method = json[findMethodIndex(json, name)];
|
||||||
var result = name + '(';
|
var result = name + '(';
|
||||||
|
|
|
@ -33,6 +33,16 @@ if (process.env.NODE_ENV !== 'build') {
|
||||||
var web3 = require('./web3'); // jshint ignore:line
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoProvider object prototype is implementing 'provider protocol'
|
||||||
|
* Automatically tries to setup correct provider(Qt, WebSockets or HttpRpc)
|
||||||
|
* First it checkes if we are ethereum browser (if navigator.qt object is available)
|
||||||
|
* if yes, we are using QtProvider
|
||||||
|
* if no, we check if it is possible to establish websockets connection with ethereum (ws://localhost:40404/eth is default)
|
||||||
|
* if it's not possible, we are using httprpc provider (http://localhost:8080)
|
||||||
|
* The constructor allows you to specify uris on which we are trying to connect over http or websockets
|
||||||
|
* You can do that by passing objects with fields httrpc and websockets
|
||||||
|
*/
|
||||||
var AutoProvider = function (userOptions) {
|
var AutoProvider = function (userOptions) {
|
||||||
if (web3.haveProvider()) {
|
if (web3.haveProvider()) {
|
||||||
return;
|
return;
|
||||||
|
@ -81,6 +91,8 @@ var AutoProvider = function (userOptions) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Sends message forward to the provider, that is being used
|
||||||
|
/// if provider is not yet set, enqueues the message
|
||||||
AutoProvider.prototype.send = function (payload) {
|
AutoProvider.prototype.send = function (payload) {
|
||||||
if (this.provider) {
|
if (this.provider) {
|
||||||
this.provider.send(payload);
|
this.provider.send(payload);
|
||||||
|
@ -89,6 +101,7 @@ AutoProvider.prototype.send = function (payload) {
|
||||||
this.sendQueue.push(payload);
|
this.sendQueue.push(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// On incoming message sends the message to the provider that is currently being used
|
||||||
Object.defineProperty(AutoProvider.prototype, 'onmessage', {
|
Object.defineProperty(AutoProvider.prototype, 'onmessage', {
|
||||||
set: function (handler) {
|
set: function (handler) {
|
||||||
if (this.provider) {
|
if (this.provider) {
|
||||||
|
|
|
@ -27,9 +27,29 @@ if (process.env.NODE_ENV !== 'build') {
|
||||||
|
|
||||||
var abi = require('./abi');
|
var abi = require('./abi');
|
||||||
|
|
||||||
// method signature length in bytes
|
/// method signature length in bytes
|
||||||
var ETH_METHOD_SIGNATURE_LENGTH = 4;
|
var ETH_METHOD_SIGNATURE_LENGTH = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should be called when we want to call / transact some solidity method from javascript
|
||||||
|
* it returns an object which has same methods available as solidity contract description
|
||||||
|
* usage example:
|
||||||
|
*
|
||||||
|
* var abi = [{
|
||||||
|
* name: 'myMethod',
|
||||||
|
* inputs: [{ name: 'a', type: 'string' }],
|
||||||
|
* outputs: [{name: 'd', type: 'string' }]
|
||||||
|
* }]; // contract abi
|
||||||
|
*
|
||||||
|
* var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object
|
||||||
|
*
|
||||||
|
* myContract.myMethod('this is test string param for call').call(); // myMethod call
|
||||||
|
* myContract.myMethod('this is test string param for transact').transact() // myMethod transact
|
||||||
|
*
|
||||||
|
* @param address - address of the contract, which should be called
|
||||||
|
* @param desc - abi json description of the contract, which is being created
|
||||||
|
* @returns contract object
|
||||||
|
*/
|
||||||
var contract = function (address, desc) {
|
var contract = function (address, desc) {
|
||||||
var inputParser = abi.inputParser(desc);
|
var inputParser = abi.inputParser(desc);
|
||||||
var outputParser = abi.outputParser(desc);
|
var outputParser = abi.outputParser(desc);
|
||||||
|
@ -70,3 +90,4 @@ var contract = function (address, desc) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = contract;
|
module.exports = contract;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file filter.js
|
||||||
|
* @authors:
|
||||||
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* Gav Wood <g@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
/// should be used when we want to watch something
|
||||||
|
/// it's using inner polling mechanism and is notified about changes
|
||||||
|
var Filter = function(options, impl) {
|
||||||
|
this.impl = impl;
|
||||||
|
this.callbacks = [];
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.promise = impl.newFilter(options);
|
||||||
|
this.promise.then(function (id) {
|
||||||
|
self.id = id;
|
||||||
|
web3.on(impl.changed, id, self.trigger.bind(self));
|
||||||
|
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/// alias for changed*
|
||||||
|
Filter.prototype.arrived = function(callback) {
|
||||||
|
this.changed(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// gets called when there is new eth/shh message
|
||||||
|
Filter.prototype.changed = function(callback) {
|
||||||
|
var self = this;
|
||||||
|
this.promise.then(function(id) {
|
||||||
|
self.callbacks.push(callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/// trigger calling new message from people
|
||||||
|
Filter.prototype.trigger = function(messages) {
|
||||||
|
for(var i = 0; i < this.callbacks.length; i++) {
|
||||||
|
this.callbacks[i].call(this, messages);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// should be called to uninstall current filter
|
||||||
|
Filter.prototype.uninstall = function() {
|
||||||
|
var self = this;
|
||||||
|
this.promise.then(function (id) {
|
||||||
|
self.impl.uninstallFilter(id);
|
||||||
|
web3.provider.stopPolling(id);
|
||||||
|
web3.off(impl.changed, id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/// should be called to manually trigger getting latest messages from the client
|
||||||
|
Filter.prototype.messages = function() {
|
||||||
|
var self = this;
|
||||||
|
return this.promise.then(function (id) {
|
||||||
|
return self.impl.getMessages(id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/// alias for messages
|
||||||
|
Filter.prototype.logs = function () {
|
||||||
|
return this.messages();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Filter;
|
|
@ -26,11 +26,21 @@ if (process.env.NODE_ENV !== 'build') {
|
||||||
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
|
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpRpcProvider object prototype is implementing 'provider protocol'
|
||||||
|
* Should be used when we want to connect to ethereum backend over http && jsonrpc
|
||||||
|
* It's compatible with cpp client
|
||||||
|
* The contructor allows to specify host uri
|
||||||
|
* This provider is using in-browser polling mechanism
|
||||||
|
*/
|
||||||
var HttpRpcProvider = function (host) {
|
var HttpRpcProvider = function (host) {
|
||||||
this.handlers = [];
|
this.handlers = [];
|
||||||
this.host = host;
|
this.host = host;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Transforms inner message to proper jsonrpc object
|
||||||
|
/// @param inner message object
|
||||||
|
/// @returns jsonrpc object
|
||||||
function formatJsonRpcObject(object) {
|
function formatJsonRpcObject(object) {
|
||||||
return {
|
return {
|
||||||
jsonrpc: '2.0',
|
jsonrpc: '2.0',
|
||||||
|
@ -40,6 +50,9 @@ function formatJsonRpcObject(object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transforms jsonrpc object to inner message
|
||||||
|
/// @param incoming jsonrpc message
|
||||||
|
/// @returns inner message object
|
||||||
function formatJsonRpcMessage(message) {
|
function formatJsonRpcMessage(message) {
|
||||||
var object = JSON.parse(message);
|
var object = JSON.parse(message);
|
||||||
|
|
||||||
|
@ -50,6 +63,10 @@ function formatJsonRpcMessage(message) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Asynchronously sends request to server
|
||||||
|
/// @param payload is inner message object
|
||||||
|
/// @param cb is callback which is being called when response is comes back
|
||||||
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
|
HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
|
||||||
var data = formatJsonRpcObject(payload);
|
var data = formatJsonRpcObject(payload);
|
||||||
|
|
||||||
|
@ -63,6 +80,11 @@ HttpRpcProvider.prototype.sendRequest = function (payload, cb) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called when we want to send single api request to server
|
||||||
|
/// Asynchronous
|
||||||
|
/// On response it passes message to handlers
|
||||||
|
/// @param payload is inner message object
|
||||||
HttpRpcProvider.prototype.send = function (payload) {
|
HttpRpcProvider.prototype.send = function (payload) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.sendRequest(payload, function (request) {
|
this.sendRequest(payload, function (request) {
|
||||||
|
@ -72,6 +94,13 @@ HttpRpcProvider.prototype.send = function (payload) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called only for polling requests
|
||||||
|
/// Asynchronous
|
||||||
|
/// On response it passege message to handlers, but only if message's result is true or not empty array
|
||||||
|
/// Otherwise response is being silently ignored
|
||||||
|
/// @param payload is inner message object
|
||||||
|
/// @id is id of poll that we are calling
|
||||||
HttpRpcProvider.prototype.poll = function (payload, id) {
|
HttpRpcProvider.prototype.poll = function (payload, id) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.sendRequest(payload, function (request) {
|
this.sendRequest(payload, function (request) {
|
||||||
|
@ -85,6 +114,8 @@ HttpRpcProvider.prototype.poll = function (payload, id) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object property
|
||||||
|
/// Should be used to set message handlers for this provider
|
||||||
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
|
Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
|
||||||
set: function (handler) {
|
set: function (handler) {
|
||||||
this.handlers.push(handler);
|
this.handlers.push(handler);
|
||||||
|
@ -92,3 +123,4 @@ Object.defineProperty(HttpRpcProvider.prototype, "onmessage", {
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = HttpRpcProvider;
|
module.exports = HttpRpcProvider;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
This file is part of ethereum.js.
|
||||||
|
|
||||||
|
ethereum.js is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ethereum.js is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/** @file providermanager.js
|
||||||
|
* @authors:
|
||||||
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
* Marian Oancea <marian@ethdev.com>
|
||||||
|
* Gav Wood <g@ethdev.com>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: is these line is supposed to be here?
|
||||||
|
if (process.env.NODE_ENV !== 'build') {
|
||||||
|
var web3 = require('./web3'); // jshint ignore:line
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider manager object prototype
|
||||||
|
* It's responsible for passing messages to providers
|
||||||
|
* If no provider is set it's responsible for queuing requests
|
||||||
|
* It's also responsible for polling the ethereum node for incoming messages
|
||||||
|
* Default poll timeout is 12 seconds
|
||||||
|
* If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling,
|
||||||
|
* and provider manager polling mechanism is not used
|
||||||
|
*/
|
||||||
|
var ProviderManager = function() {
|
||||||
|
this.queued = [];
|
||||||
|
this.polls = [];
|
||||||
|
this.ready = false;
|
||||||
|
this.provider = undefined;
|
||||||
|
this.id = 1;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var poll = function () {
|
||||||
|
if (self.provider && self.provider.poll) {
|
||||||
|
self.polls.forEach(function (data) {
|
||||||
|
data.data._id = self.id;
|
||||||
|
self.id++;
|
||||||
|
self.provider.poll(data.data, data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout(poll, 12000);
|
||||||
|
};
|
||||||
|
poll();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// sends outgoing requests, if provider is not available, enqueue the request
|
||||||
|
ProviderManager.prototype.send = function(data, cb) {
|
||||||
|
data._id = this.id;
|
||||||
|
if (cb) {
|
||||||
|
web3._callbacks[data._id] = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.args = data.args || [];
|
||||||
|
this.id++;
|
||||||
|
|
||||||
|
if(this.provider !== undefined) {
|
||||||
|
this.provider.send(data);
|
||||||
|
} else {
|
||||||
|
console.warn("provider is not set");
|
||||||
|
this.queued.push(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// setups provider, which will be used for sending messages
|
||||||
|
ProviderManager.prototype.set = function(provider) {
|
||||||
|
if(this.provider !== undefined && this.provider.unload !== undefined) {
|
||||||
|
this.provider.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.provider = provider;
|
||||||
|
this.ready = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// resends queued messages
|
||||||
|
ProviderManager.prototype.sendQueued = function() {
|
||||||
|
for(var i = 0; this.queued.length; i++) {
|
||||||
|
// Resend
|
||||||
|
this.send(this.queued[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @returns true if the provider i properly set
|
||||||
|
ProviderManager.prototype.installed = function() {
|
||||||
|
return this.provider !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// this method is only used, when we do not have native qt bindings and have to do polling on our own
|
||||||
|
/// should be callled, on start watching for eth/shh changes
|
||||||
|
ProviderManager.prototype.startPolling = function (data, pollId) {
|
||||||
|
if (!this.provider || !this.provider.poll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.polls.push({data: data, id: pollId});
|
||||||
|
};
|
||||||
|
|
||||||
|
/// should be called to stop polling for certain watch changes
|
||||||
|
ProviderManager.prototype.stopPolling = function (pollId) {
|
||||||
|
for (var i = this.polls.length; i--;) {
|
||||||
|
var poll = this.polls[i];
|
||||||
|
if (poll.id === pollId) {
|
||||||
|
this.polls.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProviderManager;
|
||||||
|
|
12
lib/qt.js
12
lib/qt.js
|
@ -21,6 +21,11 @@
|
||||||
* @date 2014
|
* @date 2014
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QtProvider object prototype is implementing 'provider protocol'
|
||||||
|
* Should be used inside ethereum browser. It's compatible with cpp and go clients.
|
||||||
|
* It uses navigator.qt object to pass the messages to native bindings
|
||||||
|
*/
|
||||||
var QtProvider = function() {
|
var QtProvider = function() {
|
||||||
this.handlers = [];
|
this.handlers = [];
|
||||||
|
|
||||||
|
@ -32,10 +37,17 @@ var QtProvider = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called when we want to send single api request to native bindings
|
||||||
|
/// Asynchronous
|
||||||
|
/// Response will be received by navigator.qt.onmessage method and passed to handlers
|
||||||
|
/// @param payload is inner message object
|
||||||
QtProvider.prototype.send = function(payload) {
|
QtProvider.prototype.send = function(payload) {
|
||||||
navigator.qt.postMessage(JSON.stringify(payload));
|
navigator.qt.postMessage(JSON.stringify(payload));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object property
|
||||||
|
/// Should be used to set message handlers for this provider
|
||||||
Object.defineProperty(QtProvider.prototype, "onmessage", {
|
Object.defineProperty(QtProvider.prototype, "onmessage", {
|
||||||
set: function(handler) {
|
set: function(handler) {
|
||||||
this.handlers.push(handler);
|
this.handlers.push(handler);
|
||||||
|
|
180
lib/web3.js
180
lib/web3.js
|
@ -14,7 +14,7 @@
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/** @file main.js
|
/** @file web3.js
|
||||||
* @authors:
|
* @authors:
|
||||||
* Jeffrey Wilcke <jeff@ethdev.com>
|
* Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
* Marek Kotewicz <marek@ethdev.com>
|
* Marek Kotewicz <marek@ethdev.com>
|
||||||
|
@ -23,6 +23,12 @@
|
||||||
* @date 2014
|
* @date 2014
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var Filter = require('./filter');
|
||||||
|
var ProviderManager = require('./providermanager');
|
||||||
|
|
||||||
|
/// Recursively resolves all promises in given object and replaces the resolved values with promises
|
||||||
|
/// @param any object/array/promise/anything else..
|
||||||
|
/// @returns (resolves) object with replaced promises with their result
|
||||||
function flattenPromise (obj) {
|
function flattenPromise (obj) {
|
||||||
if (obj instanceof Promise) {
|
if (obj instanceof Promise) {
|
||||||
return Promise.resolve(obj);
|
return Promise.resolve(obj);
|
||||||
|
@ -62,12 +68,14 @@ function flattenPromise (obj) {
|
||||||
return Promise.resolve(obj);
|
return Promise.resolve(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3 api methods
|
||||||
var web3Methods = function () {
|
var web3Methods = function () {
|
||||||
return [
|
return [
|
||||||
{ name: 'sha3', call: 'web3_sha3' }
|
{ name: 'sha3', call: 'web3_sha3' }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.eth api methods
|
||||||
var ethMethods = function () {
|
var ethMethods = function () {
|
||||||
var blockCall = function (args) {
|
var blockCall = function (args) {
|
||||||
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
|
return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
|
||||||
|
@ -101,6 +109,7 @@ var ethMethods = function () {
|
||||||
return methods;
|
return methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.eth api properties
|
||||||
var ethProperties = function () {
|
var ethProperties = function () {
|
||||||
return [
|
return [
|
||||||
{ name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
|
{ name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
|
||||||
|
@ -115,6 +124,7 @@ var ethProperties = function () {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.db api methods
|
||||||
var dbMethods = function () {
|
var dbMethods = function () {
|
||||||
return [
|
return [
|
||||||
{ name: 'put', call: 'db_put' },
|
{ name: 'put', call: 'db_put' },
|
||||||
|
@ -124,6 +134,7 @@ var dbMethods = function () {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.shh api methods
|
||||||
var shhMethods = function () {
|
var shhMethods = function () {
|
||||||
return [
|
return [
|
||||||
{ name: 'post', call: 'shh_post' },
|
{ name: 'post', call: 'shh_post' },
|
||||||
|
@ -134,6 +145,7 @@ var shhMethods = function () {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.eth.watch api methods
|
||||||
var ethWatchMethods = function () {
|
var ethWatchMethods = function () {
|
||||||
var newFilter = function (args) {
|
var newFilter = function (args) {
|
||||||
return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
|
return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
|
||||||
|
@ -146,6 +158,7 @@ var ethWatchMethods = function () {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @returns an array of objects describing web3.shh.watch api methods
|
||||||
var shhWatchMethods = function () {
|
var shhWatchMethods = function () {
|
||||||
return [
|
return [
|
||||||
{ name: 'newFilter', call: 'shh_newFilter' },
|
{ name: 'newFilter', call: 'shh_newFilter' },
|
||||||
|
@ -154,6 +167,8 @@ var shhWatchMethods = function () {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// creates methods in a given object based on method description on input
|
||||||
|
/// setups api calls for these methods
|
||||||
var setupMethods = function (obj, methods) {
|
var setupMethods = function (obj, methods) {
|
||||||
methods.forEach(function (method) {
|
methods.forEach(function (method) {
|
||||||
obj[method.name] = function () {
|
obj[method.name] = function () {
|
||||||
|
@ -177,6 +192,8 @@ var setupMethods = function (obj, methods) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// creates properties in a given object based on properties description on input
|
||||||
|
/// setups api calls for these properties
|
||||||
var setupProperties = function (obj, properties) {
|
var setupProperties = function (obj, properties) {
|
||||||
properties.forEach(function (property) {
|
properties.forEach(function (property) {
|
||||||
var proto = {};
|
var proto = {};
|
||||||
|
@ -221,7 +238,7 @@ var decToHex = function (dec) {
|
||||||
return parseInt(dec).toString(16);
|
return parseInt(dec).toString(16);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// setups web3 object, and it's in-browser executed methods
|
||||||
var web3 = {
|
var web3 = {
|
||||||
_callbacks: {},
|
_callbacks: {},
|
||||||
_events: {},
|
_events: {},
|
||||||
|
@ -237,6 +254,7 @@ var web3 = {
|
||||||
return hex;
|
return hex;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// @returns ascii string representation of hex value prefixed with 0x
|
||||||
toAscii: function(hex) {
|
toAscii: function(hex) {
|
||||||
// Find termination
|
// Find termination
|
||||||
var str = "";
|
var str = "";
|
||||||
|
@ -244,17 +262,18 @@ var web3 = {
|
||||||
if (hex.substring(0, 2) === '0x')
|
if (hex.substring(0, 2) === '0x')
|
||||||
i = 2;
|
i = 2;
|
||||||
for(; i < l; i+=2) {
|
for(; i < l; i+=2) {
|
||||||
var code = hex.charCodeAt(i);
|
var code = parseInt(hex.substr(i, 2), 16);
|
||||||
if(code === 0) {
|
if(code === 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
str += String.fromCharCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// @returns hex representation (prefixed by 0x) of ascii string
|
||||||
fromAscii: function(str, pad) {
|
fromAscii: function(str, pad) {
|
||||||
pad = pad === undefined ? 0 : pad;
|
pad = pad === undefined ? 0 : pad;
|
||||||
var hex = this.toHex(str);
|
var hex = this.toHex(str);
|
||||||
|
@ -263,14 +282,17 @@ var web3 = {
|
||||||
return "0x" + hex;
|
return "0x" + hex;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// @returns decimal representaton of hex value prefixed by 0x
|
||||||
toDecimal: function (val) {
|
toDecimal: function (val) {
|
||||||
return hexToDec(val.substring(2));
|
return hexToDec(val.substring(2));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// @returns hex representation (prefixed by 0x) of decimal value
|
||||||
fromDecimal: function (val) {
|
fromDecimal: function (val) {
|
||||||
return "0x" + decToHex(val);
|
return "0x" + decToHex(val);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// used to transform value/string to eth string
|
||||||
toEth: function(str) {
|
toEth: function(str) {
|
||||||
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
|
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
|
||||||
var unit = 0;
|
var unit = 0;
|
||||||
|
@ -294,24 +316,24 @@ var web3 = {
|
||||||
return s + ' ' + units[unit];
|
return s + ' ' + units[unit];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// eth object prototype
|
||||||
eth: {
|
eth: {
|
||||||
prototype: Object(), // jshint ignore:line
|
|
||||||
watch: function (params) {
|
watch: function (params) {
|
||||||
return new Filter(params, ethWatch);
|
return new Filter(params, ethWatch);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
db: {
|
/// db object prototype
|
||||||
prototype: Object() // jshint ignore:line
|
db: {},
|
||||||
},
|
|
||||||
|
|
||||||
|
/// shh object prototype
|
||||||
shh: {
|
shh: {
|
||||||
prototype: Object(), // jshint ignore:line
|
|
||||||
watch: function (params) {
|
watch: function (params) {
|
||||||
return new Filter(params, shhWatch);
|
return new Filter(params, shhWatch);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// used by filter to register callback with given id
|
||||||
on: function(event, id, cb) {
|
on: function(event, id, cb) {
|
||||||
if(web3._events[event] === undefined) {
|
if(web3._events[event] === undefined) {
|
||||||
web3._events[event] = {};
|
web3._events[event] = {};
|
||||||
|
@ -321,6 +343,7 @@ var web3 = {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// used by filter to unregister callback with given id
|
||||||
off: function(event, id) {
|
off: function(event, id) {
|
||||||
if(web3._events[event] !== undefined) {
|
if(web3._events[event] !== undefined) {
|
||||||
delete web3._events[event][id];
|
delete web3._events[event][id];
|
||||||
|
@ -329,6 +352,7 @@ var web3 = {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// used to trigger callback registered by filter
|
||||||
trigger: function(event, id, data) {
|
trigger: function(event, id, data) {
|
||||||
var callbacks = web3._events[event];
|
var callbacks = web3._events[event];
|
||||||
if (!callbacks || !callbacks[id]) {
|
if (!callbacks || !callbacks[id]) {
|
||||||
|
@ -336,9 +360,15 @@ var web3 = {
|
||||||
}
|
}
|
||||||
var cb = callbacks[id];
|
var cb = callbacks[id];
|
||||||
cb(data);
|
cb(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
/// @returns true if provider is installed
|
||||||
|
haveProvider: function() {
|
||||||
|
return !!web3.provider.provider;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// setups all api methods
|
||||||
setupMethods(web3, web3Methods());
|
setupMethods(web3, web3Methods());
|
||||||
setupMethods(web3.eth, ethMethods());
|
setupMethods(web3.eth, ethMethods());
|
||||||
setupProperties(web3.eth, ethProperties());
|
setupProperties(web3.eth, ethProperties());
|
||||||
|
@ -348,86 +378,15 @@ setupMethods(web3.shh, shhMethods());
|
||||||
var ethWatch = {
|
var ethWatch = {
|
||||||
changed: 'eth_changed'
|
changed: 'eth_changed'
|
||||||
};
|
};
|
||||||
|
|
||||||
setupMethods(ethWatch, ethWatchMethods());
|
setupMethods(ethWatch, ethWatchMethods());
|
||||||
|
|
||||||
var shhWatch = {
|
var shhWatch = {
|
||||||
changed: 'shh_changed'
|
changed: 'shh_changed'
|
||||||
};
|
};
|
||||||
|
|
||||||
setupMethods(shhWatch, shhWatchMethods());
|
setupMethods(shhWatch, shhWatchMethods());
|
||||||
|
|
||||||
var ProviderManager = function() {
|
|
||||||
this.queued = [];
|
|
||||||
this.polls = [];
|
|
||||||
this.ready = false;
|
|
||||||
this.provider = undefined;
|
|
||||||
this.id = 1;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var poll = function () {
|
|
||||||
if (self.provider && self.provider.poll) {
|
|
||||||
self.polls.forEach(function (data) {
|
|
||||||
data.data._id = self.id;
|
|
||||||
self.id++;
|
|
||||||
self.provider.poll(data.data, data.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setTimeout(poll, 12000);
|
|
||||||
};
|
|
||||||
poll();
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.send = function(data, cb) {
|
|
||||||
data._id = this.id;
|
|
||||||
if (cb) {
|
|
||||||
web3._callbacks[data._id] = cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.args = data.args || [];
|
|
||||||
this.id++;
|
|
||||||
|
|
||||||
if(this.provider !== undefined) {
|
|
||||||
this.provider.send(data);
|
|
||||||
} else {
|
|
||||||
console.warn("provider is not set");
|
|
||||||
this.queued.push(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.set = function(provider) {
|
|
||||||
if(this.provider !== undefined && this.provider.unload !== undefined) {
|
|
||||||
this.provider.unload();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.provider = provider;
|
|
||||||
this.ready = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.sendQueued = function() {
|
|
||||||
for(var i = 0; this.queued.length; i++) {
|
|
||||||
// Resend
|
|
||||||
this.send(this.queued[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.installed = function() {
|
|
||||||
return this.provider !== undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.startPolling = function (data, pollId) {
|
|
||||||
if (!this.provider || !this.provider.poll) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.polls.push({data: data, id: pollId});
|
|
||||||
};
|
|
||||||
|
|
||||||
ProviderManager.prototype.stopPolling = function (pollId) {
|
|
||||||
for (var i = this.polls.length; i--;) {
|
|
||||||
var poll = this.polls[i];
|
|
||||||
if (poll.id === pollId) {
|
|
||||||
this.polls.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
web3.provider = new ProviderManager();
|
web3.provider = new ProviderManager();
|
||||||
|
|
||||||
web3.setProvider = function(provider) {
|
web3.setProvider = function(provider) {
|
||||||
|
@ -436,60 +395,7 @@ web3.setProvider = function(provider) {
|
||||||
web3.provider.sendQueued();
|
web3.provider.sendQueued();
|
||||||
};
|
};
|
||||||
|
|
||||||
web3.haveProvider = function() {
|
/// callled when there is new incoming message
|
||||||
return !!web3.provider.provider;
|
|
||||||
};
|
|
||||||
|
|
||||||
var Filter = function(options, impl) {
|
|
||||||
this.impl = impl;
|
|
||||||
this.callbacks = [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.promise = impl.newFilter(options);
|
|
||||||
this.promise.then(function (id) {
|
|
||||||
self.id = id;
|
|
||||||
web3.on(impl.changed, id, self.trigger.bind(self));
|
|
||||||
web3.provider.startPolling({call: impl.changed, args: [id]}, id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.arrived = function(callback) {
|
|
||||||
this.changed(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.changed = function(callback) {
|
|
||||||
var self = this;
|
|
||||||
this.promise.then(function(id) {
|
|
||||||
self.callbacks.push(callback);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.trigger = function(messages) {
|
|
||||||
for(var i = 0; i < this.callbacks.length; i++) {
|
|
||||||
this.callbacks[i].call(this, messages);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.uninstall = function() {
|
|
||||||
var self = this;
|
|
||||||
this.promise.then(function (id) {
|
|
||||||
self.impl.uninstallFilter(id);
|
|
||||||
web3.provider.stopPolling(id);
|
|
||||||
web3.off(impl.changed, id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.messages = function() {
|
|
||||||
var self = this;
|
|
||||||
return this.promise.then(function (id) {
|
|
||||||
return self.impl.getMessages(id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Filter.prototype.logs = function () {
|
|
||||||
return this.messages();
|
|
||||||
};
|
|
||||||
|
|
||||||
function messageHandler(data) {
|
function messageHandler(data) {
|
||||||
if(data._event !== undefined) {
|
if(data._event !== undefined) {
|
||||||
web3.trigger(data._event, data._id, data.data);
|
web3.trigger(data._event, data._id, data.data);
|
||||||
|
|
|
@ -27,9 +27,17 @@ if (process.env.NODE_ENV !== 'build') {
|
||||||
var WebSocket = require('ws'); // jshint ignore:line
|
var WebSocket = require('ws'); // jshint ignore:line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocketProvider object prototype is implementing 'provider protocol'
|
||||||
|
* Should be used when we want to connect to ethereum backend over websockets
|
||||||
|
* It's compatible with go client
|
||||||
|
* The constructor allows to specify host uri
|
||||||
|
*/
|
||||||
var WebSocketProvider = function(host) {
|
var WebSocketProvider = function(host) {
|
||||||
|
|
||||||
// onmessage handlers
|
// onmessage handlers
|
||||||
this.handlers = [];
|
this.handlers = [];
|
||||||
|
|
||||||
// queue will be filled with messages if send is invoked before the ws is ready
|
// queue will be filled with messages if send is invoked before the ws is ready
|
||||||
this.queued = [];
|
this.queued = [];
|
||||||
this.ready = false;
|
this.ready = false;
|
||||||
|
@ -46,15 +54,20 @@ var WebSocketProvider = function(host) {
|
||||||
this.ws.onopen = function() {
|
this.ws.onopen = function() {
|
||||||
self.ready = true;
|
self.ready = true;
|
||||||
|
|
||||||
for(var i = 0; i < self.queued.length; i++) {
|
for (var i = 0; i < self.queued.length; i++) {
|
||||||
// Resend
|
// Resend
|
||||||
self.send(self.queued[i]);
|
self.send(self.queued[i]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called when we want to send single api request to server
|
||||||
|
/// Asynchronous, it's using websockets
|
||||||
|
/// Response for the call will be received by ws.onmessage
|
||||||
|
/// @param payload is inner message object
|
||||||
WebSocketProvider.prototype.send = function(payload) {
|
WebSocketProvider.prototype.send = function(payload) {
|
||||||
if(this.ready) {
|
if (this.ready) {
|
||||||
var data = JSON.stringify(payload);
|
var data = JSON.stringify(payload);
|
||||||
|
|
||||||
this.ws.send(data);
|
this.ws.send(data);
|
||||||
|
@ -63,13 +76,20 @@ WebSocketProvider.prototype.send = function(payload) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called to add handlers
|
||||||
WebSocketProvider.prototype.onMessage = function(handler) {
|
WebSocketProvider.prototype.onMessage = function(handler) {
|
||||||
this.handlers.push(handler);
|
this.handlers.push(handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object method
|
||||||
|
/// Should be called to close websockets connection
|
||||||
WebSocketProvider.prototype.unload = function() {
|
WebSocketProvider.prototype.unload = function() {
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Prototype object property
|
||||||
|
/// Should be used to set message handlers for this provider
|
||||||
Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
|
Object.defineProperty(WebSocketProvider.prototype, "onmessage", {
|
||||||
set: function(provider) { this.onMessage(provider); }
|
set: function(provider) { this.onMessage(provider); }
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var abi = require('../lib/abi.js');
|
var abi = require('../lib/abi.js');
|
||||||
|
var clone = function (object) { return JSON.parse(JSON.stringify(object)); };
|
||||||
|
|
||||||
describe('abi', function() {
|
var description = [{
|
||||||
describe('inputParser', function() {
|
"name": "test",
|
||||||
it('should parse ...', function() {
|
"inputs": [{
|
||||||
|
|
||||||
var desc = [{
|
|
||||||
"name": "multiply",
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "a",
|
"name": "a",
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
|
@ -19,19 +15,533 @@ describe('abi', function() {
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}];
|
||||||
|
|
||||||
|
describe('abi', function() {
|
||||||
|
describe('inputParser', function() {
|
||||||
|
it('should parse input uint', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "uint" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input uint128', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "uint128" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input uint256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "uint256" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input int', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "int" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
|
||||||
|
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input int128', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "int128" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
|
||||||
|
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input int256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "int256" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(10), "000000000000000000000000000000000000000000000000000000000000000a");
|
||||||
|
assert.equal(parser.test(-1), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
assert.equal(parser.test(-2), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
|
||||||
|
assert.equal(parser.test(-16), "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input bool', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: 'bool' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test(true), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test(false), "0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input hash', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "hash" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input hash256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "hash256" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should parse input hash160', function() {
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "hash160" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input address', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "address" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x407d73d8a49eeb85d32cf465507dd71d507100c1"), "000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse input string', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "string" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test('hello'), "68656c6c6f000000000000000000000000000000000000000000000000000000");
|
||||||
|
assert.equal(parser.test('world'), "776f726c64000000000000000000000000000000000000000000000000000000");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use proper method name', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
d[0].name = 'helloworld';
|
||||||
|
d[0].inputs = [
|
||||||
|
{ type: "int" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.helloworld(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse multiple methods', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = [{
|
||||||
|
name: "test",
|
||||||
|
inputs: [{ type: "int" }],
|
||||||
|
outputs: [{ type: "int" }]
|
||||||
|
},{
|
||||||
|
name: "test2",
|
||||||
|
inputs: [{ type: "string" }],
|
||||||
|
outputs: [{ type: "string" }]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
var iParser = abi.inputParser(desc);
|
// when
|
||||||
assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001");
|
var parser = abi.inputParser(d);
|
||||||
|
|
||||||
|
//then
|
||||||
|
assert.equal(parser.test(1), "0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
assert.equal(parser.test2('hello'), "68656c6c6f000000000000000000000000000000000000000000000000000000");
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('outputParser', function() {
|
describe('outputParser', function() {
|
||||||
it('parse ...', function() {
|
it('should parse output string', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: "string" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x68656c6c6f000000000000000000000000000000000000000000000000000000")[0], 'hello');
|
||||||
|
assert.equal(parser.test("0x776f726c64000000000000000000000000000000000000000000000000000000")[0], 'world');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should parse output uint', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'uint' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output uint256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'uint256' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output uint128', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'uint128' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output int', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'int' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output int256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'int256' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output int128', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'int128' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output hash', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'hash' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0], "0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output hash256', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'hash256' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0], "0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output hash160', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'hash160' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0], "0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")
|
||||||
|
// TODO shouldnt' the expected hash be shorter?
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output address', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'address' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0], "0x407d73d8a49eeb85d32cf465507dd71d507100c1")
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse output bool', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: 'bool' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000001")[0], true);
|
||||||
|
assert.equal(parser.test("000000000000000000000000000000000000000000000000000000000000000000")[0], false);
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse multiple output strings', function() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: "string" },
|
||||||
|
{ type: "string" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.test("0x68656c6c6f000000000000000000000000000000000000000000000000000000776f726c64000000000000000000000000000000000000000000000000000000")[0], 'hello');
|
||||||
|
assert.equal(parser.test("0x68656c6c6f000000000000000000000000000000000000000000000000000000776f726c64000000000000000000000000000000000000000000000000000000")[1], 'world');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use proper method name', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = clone(description);
|
||||||
|
d[0].name = 'helloworld';
|
||||||
|
d[0].outputs = [
|
||||||
|
{ type: "int" }
|
||||||
|
];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should parse multiple methods', function () {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var d = [{
|
||||||
|
name: "test",
|
||||||
|
inputs: [{ type: "int" }],
|
||||||
|
outputs: [{ type: "int" }]
|
||||||
|
},{
|
||||||
|
name: "test2",
|
||||||
|
inputs: [{ type: "string" }],
|
||||||
|
outputs: [{ type: "string" }]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// when
|
||||||
|
var parser = abi.outputParser(d);
|
||||||
|
|
||||||
|
//then
|
||||||
|
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
|
||||||
|
assert.equal(parser.test2("0x68656c6c6f000000000000000000000000000000000000000000000000000000")[0], "hello");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,10 @@ web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080'));
|
||||||
|
|
||||||
describe('web3', function() {
|
describe('web3', function() {
|
||||||
describe('db', function() {
|
describe('db', function() {
|
||||||
it('should have all methods implemented', function() {
|
|
||||||
u.methodExists(web3.db, 'put');
|
u.methodExists(web3.db, 'put');
|
||||||
u.methodExists(web3.db, 'get');
|
u.methodExists(web3.db, 'get');
|
||||||
u.methodExists(web3.db, 'putString');
|
u.methodExists(web3.db, 'putString');
|
||||||
u.methodExists(web3.db, 'getString');
|
u.methodExists(web3.db, 'getString');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080'));
|
||||||
|
|
||||||
describe('web3', function() {
|
describe('web3', function() {
|
||||||
describe('eth', function() {
|
describe('eth', function() {
|
||||||
it('should have all methods implemented', function() {
|
|
||||||
u.methodExists(web3.eth, 'balanceAt');
|
u.methodExists(web3.eth, 'balanceAt');
|
||||||
u.methodExists(web3.eth, 'stateAt');
|
u.methodExists(web3.eth, 'stateAt');
|
||||||
u.methodExists(web3.eth, 'storageAt');
|
u.methodExists(web3.eth, 'storageAt');
|
||||||
|
@ -23,9 +22,7 @@ describe('web3', function() {
|
||||||
u.methodExists(web3.eth, 'solidity');
|
u.methodExists(web3.eth, 'solidity');
|
||||||
u.methodExists(web3.eth, 'serpent');
|
u.methodExists(web3.eth, 'serpent');
|
||||||
u.methodExists(web3.eth, 'logs');
|
u.methodExists(web3.eth, 'logs');
|
||||||
});
|
|
||||||
|
|
||||||
it('should have all properties implemented', function () {
|
|
||||||
u.propertyExists(web3.eth, 'coinbase');
|
u.propertyExists(web3.eth, 'coinbase');
|
||||||
u.propertyExists(web3.eth, 'listening');
|
u.propertyExists(web3.eth, 'listening');
|
||||||
u.propertyExists(web3.eth, 'mining');
|
u.propertyExists(web3.eth, 'mining');
|
||||||
|
@ -36,7 +33,6 @@ describe('web3', function() {
|
||||||
u.propertyExists(web3.eth, 'defaultBlock');
|
u.propertyExists(web3.eth, 'defaultBlock');
|
||||||
u.propertyExists(web3.eth, 'number');
|
u.propertyExists(web3.eth, 'number');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
--reporter Spec
|
--reporter spec
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,11 @@ web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080'));
|
||||||
|
|
||||||
describe('web3', function() {
|
describe('web3', function() {
|
||||||
describe('shh', function() {
|
describe('shh', function() {
|
||||||
it('should have all methods implemented', function() {
|
|
||||||
u.methodExists(web3.shh, 'post');
|
u.methodExists(web3.shh, 'post');
|
||||||
u.methodExists(web3.shh, 'newIdentity');
|
u.methodExists(web3.shh, 'newIdentity');
|
||||||
u.methodExists(web3.shh, 'haveIdentity');
|
u.methodExists(web3.shh, 'haveIdentity');
|
||||||
u.methodExists(web3.shh, 'newGroup');
|
u.methodExists(web3.shh, 'newGroup');
|
||||||
u.methodExists(web3.shh, 'addToGroup');
|
u.methodExists(web3.shh, 'addToGroup');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
var methodExists = function (object, method) {
|
var methodExists = function (object, method) {
|
||||||
|
it('should have method ' + method + ' implemented', function() {
|
||||||
assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented');
|
assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var propertyExists = function (object, property) {
|
var propertyExists = function (object, property) {
|
||||||
|
it('should have property ' + property + ' implemented', function() {
|
||||||
assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented');
|
assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -6,13 +6,11 @@ var u = require('./utils.js');
|
||||||
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
||||||
|
|
||||||
describe('web3', function() {
|
describe('web3', function() {
|
||||||
it('should have all methods implemented', function() {
|
|
||||||
u.methodExists(web3, 'sha3');
|
u.methodExists(web3, 'sha3');
|
||||||
u.methodExists(web3, 'toAscii');
|
u.methodExists(web3, 'toAscii');
|
||||||
u.methodExists(web3, 'fromAscii');
|
u.methodExists(web3, 'fromAscii');
|
||||||
u.methodExists(web3, 'toFixed');
|
u.methodExists(web3, 'toFixed');
|
||||||
u.methodExists(web3, 'fromFixed');
|
u.methodExists(web3, 'fromFixed');
|
||||||
u.methodExists(web3, 'offset');
|
u.methodExists(web3, 'offset');
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue