Browse Source

Squashed 'libjsqrc/ethereumjs/' changes from eceeda7..73b9ed2

73b9ed2 rename to web3
c80ede5 fixed spelling in package description
67f0a75 version 0.2.4
e2990ae web3.eth.getBlockTransactionCount accepts pending/latest/earliest params
94429ff version 0.2.3
f9a5206 more tests for web3.eth.getBalance
31e046d Merge branch 'master' into develop
5e15037 fixed formatting address
b7a03cd version 0.2.2
2536888 let travis check if npm package is not broken
92aba81 merge master, gulp
e6a76ff Merge branch 'master' into develop
57d9f1f removed deprecated && unused lines from contract.js
5885bfe test for #128
e53f316 tests for transaction && call
31220d5 removed deprecated code in contract.js
b837667 unified asBlock from filter.js with blockNumber formatter
202a8cd #140 badge
608d211 blockNumber can be earliest
f0216fb fixed #149
e213551 tests for #144
21791f2 version 0.2.1
2262276 defaultBlockNumber accepts latest && pending
e01bb23 fixed #148 && fixed polling test
8c39acc merge branch 'develop' of https://github.com/ethereum/ethereum.js into develop
534e96d Merge branch 'master' of https://github.com/ethereum/ethereum.js
2f45df8 fix && tests for #147
e750fd9 fixed #147
e0d83d0 removed unecessary callformatter
9fc5575 version 0.2.0
2747f4c Merge pull request #137 from ethereum/sandbox
ed2b62d add whisper, network and ethereum version
aa9fc92 add whisper, network and ethereum version
f4e5a99 default log formatter, improved contract test
e9b5da4 updated package.js name to web3
8caf64a update package.json
07bcdb4 improved tests for contract.js, fixed few minor issues
1986c7f cleaned up web3.js
82b18c1 refactored filter.js
2133d27 filter changes in progress
0dbd68c Merge branch 'develop' into sandbox
17164be default toBlock && fromBlock is not null
e928e14 Merge branch 'develop' into sandbox
1a84015 fixed events topics
0beb01f test for creating signatures
a63d604 removed unused function
9d5b602 test names
a1ec149 renamed few more tests
cbf8ea1 test naming convention
04f0aa5 fixed filer.js complexity
722a5bc fixed eth.getTransaction.js location
c065f17 Merge branch 'develop' into sandbox
b78dffa small fix in filter tests
91baec2 polling tests
4f5c5fb first try to test polling
f2c8a14 removed duplicate code
9f073d9 applied fixes from cpp-ethereum
c01abfc add db tests
b247c49 add sha3 test
afd7e7b add shh tests
e7304b5 add storage tests
f32b8ad add runTest module to new tests
c52250e add block uncle and block counts
c1f5ab2 test.method.js in helpers
7df9099 moved test.utils to helpers
a4e3645 Merge branch 'develop' into sandbox
b3b95c5 add getBlock test
abe064f add Property and passing through of RPC erro texts
0b84376 fix for otto
36fe79f another fix for otto
be04c47 fixes for go otto env
c7e5d0a light browser bundle
4b37137 light browser bundle without bignumber.js
f13a727 add accounts test
b915ceb add defaultBlock back
b074a5e add check for providor async function
ae76428 Merge branch 'master' into develop
a34321d removed double FakeHTTPProvidor
7fb4405 add missing formatters, fixed tests
7511e4c fake providers moved to helpers directory
b16982b fix for polling
126b40c fixed registering coverage on providers
2924e00 fix for toHex transforming boolean
b6b809c setting up formatters for eth
99ea9cd fixed for defaultBlock formatter
33a3fc7 generic integration tests
4d1cf0b inputFormatter is an aray of functions
6b07920 add uninstall filter back
89b1ca6 first integration tests
a4cf661 tests for method.js
7519fab method.js
9423b72 Merge pull request #139 from gitter-badger/gitter-badge
24a03e0 Added Gitter badge
0898669 changes in input formatters
748cda2 requestmanager tests
476023e requestmanager refactored
e3faebe jsonrpc is an object
cbab0ae common changes in requestmanager
d408fb0 comments in requestmanager
5c1e85f requestmanager refactor in progress
f604670 tests for qtsyncprovider.js
288caf3 node-sandbox, tests for httpprovider, request manager refactor in progress
8c36a10 rename getData to getCode
de5de9e Merge branch 'develop' of https://github.com/ethereum/ethereum.js into develop
5cdea25 Merge branch 'getCode' of https://github.com/jorisbontje/ethereum.js into getCode
3550f91 Merge pull request #122 from frozeman/apiOverhaul
fb99d10 fixed meteor package
99795e3 expose bignumber.js
db7092b Merge pull request #117 from ethereum/bundle_name
5bee7be changed bundle name web3 -> ethereum.js
7ca3b40 gulp
517eff9 Merge pull request #120 from dchambers/make-browserify-compatibile
b032429 rename getData to getCode
768d4bf Make changes to 'gulpfile.js' reccomended by @debris.
0267e85 Use browserify's 'browser' field instead of 'envify' & 'unreachable-branch-transform to', plus always include 'bignumber.js' since it is needed in the browser.
cb7c209 removed unused property
12aed56 fixed #111

git-subtree-dir: libjsqrc/ethereumjs
git-subtree-split: 73b9ed29c09531817df311c2d050dec6667197e7
cl-refactor
Marek Kotewicz 10 years ago
parent
commit
6a49256775
  1. 2
      .bowerrc
  2. 1
      .gitignore
  3. 1
      .travis.yml
  4. 8
      README.md
  5. 4
      bower.json
  6. 57
      dist/ethereum.js.map
  7. 1
      dist/ethereum.min.js
  8. 1885
      dist/web3-light.js
  9. 69
      dist/web3-light.js.map
  10. 1
      dist/web3-light.min.js
  11. 5921
      dist/web3.js
  12. 69
      dist/web3.js.map
  13. 2
      dist/web3.min.js
  14. 4
      example/balance.html
  15. 3
      example/contract.html
  16. 3
      example/contract_with_array.html
  17. 3
      example/event.html
  18. 3
      example/event_inc.html
  19. 3
      example/natspec_contract.html
  20. 34
      gulpfile.js
  21. 9
      index.js
  22. 3
      karma.conf.js
  23. 20
      lib/solidity/formatters.js
  24. 4
      lib/utils/browser-bn.js
  25. 9
      lib/utils/browser-xhr.js
  26. 4
      lib/utils/config.js
  27. 68
      lib/utils/utils.js
  28. 3
      lib/version.json
  29. 288
      lib/web3.js
  30. 45
      lib/web3/contract.js
  31. 38
      lib/web3/db.js
  32. 38
      lib/web3/errors.js
  33. 243
      lib/web3/eth.js
  34. 4
      lib/web3/event.js
  35. 170
      lib/web3/filter.js
  36. 92
      lib/web3/formatters.js
  37. 56
      lib/web3/httpprovider.js
  38. 66
      lib/web3/jsonrpc.js
  39. 159
      lib/web3/method.js
  40. 13
      lib/web3/net.js
  41. 104
      lib/web3/property.js
  42. 292
      lib/web3/requestmanager.js
  43. 52
      lib/web3/shh.js
  44. 66
      lib/web3/watches.js
  45. 3
      package-init.js
  46. 8
      package.js
  47. 30
      package.json
  48. 2
      test/abi.inputParser.js
  49. 2
      test/abi.outputParser.js
  50. 229
      test/contract.js
  51. 26
      test/event.inputParser.js
  52. 6
      test/event.outputParser.js
  53. 24
      test/filter.methods.js
  54. 24
      test/formatters.inputDefaultBlockFormatter.js
  55. 3
      test/formatters.inputPostFormatter.js
  56. 11
      test/formatters.inputTransactionFormatter.js
  57. 8
      test/formatters.outputTransactionFormatter.js
  58. 68
      test/helpers/FakeHttpProvider.js
  59. 11
      test/helpers/FakeQtNavigator.js
  60. 31
      test/helpers/FakeXMLHttpRequest.js
  61. 68
      test/helpers/test.method.js
  62. 9
      test/helpers/test.utils.js
  63. 33
      test/httpprovider.js
  64. 23
      test/jsonrpc.id.js
  65. 1
      test/jsonrpc.isValidResponse.js
  66. 1
      test/jsonrpc.toBatchPayload.js
  67. 4
      test/jsonrpc.toPayload.js
  68. 44
      test/method.attachToObject.js
  69. 52
      test/method.extractCallback.js
  70. 41
      test/method.formatInput.js
  71. 43
      test/method.formatOutput.js
  72. 46
      test/method.getCall.js
  73. 47
      test/method.validateArgs.js
  74. 1
      test/mocha.opts
  75. 10
      test/net.methods.js
  76. 5
      test/node/app.js
  77. 14
      test/node/package.json
  78. 69
      test/polling.js
  79. 22
      test/qtsyncprovider.js
  80. 44
      test/requestmanager.js
  81. 45
      test/shh.filter.js
  82. 16
      test/shh.hasIdentity.js
  83. 48
      test/signature.js
  84. 2
      test/utils.extractDisplayName.js
  85. 2
      test/utils.extractTypeName.js
  86. 2
      test/utils.filters.js
  87. 2
      test/utils.fromDecimal.js
  88. 2
      test/utils.fromWei.js
  89. 4
      test/utils.isAddress.js
  90. 2
      test/utils.isBigNumber.js
  91. 2
      test/utils.isFunction.js
  92. 26
      test/utils.isJson.js
  93. 2
      test/utils.isString.js
  94. 2
      test/utils.toBigNumber.js
  95. 2
      test/utils.toDecimal.js
  96. 8
      test/utils.toHex.js
  97. 2
      test/utils.toWei.js
  98. 14
      test/web3.db.getHex.js
  99. 16
      test/web3.db.getString.js
  100. 10
      test/web3.db.methods.js

2
.bowerrc

@ -1,5 +1,5 @@
{
"directory": "example/js/",
"directory": "bower",
"cwd": "./",
"analytics": false
}

1
.gitignore

@ -17,3 +17,4 @@ example/js
node_modules
bower_components
npm-debug.log
/bower

1
.travis.yml

@ -14,4 +14,5 @@ after_script:
- npm run-script build
- npm run-script karma
- npm run-script test-coveralls
- cd test/node && npm install && node app.js

8
README.md

@ -1,9 +1,11 @@
# Ethereum JavaScript API
[![Join the chat at https://gitter.im/ethereum/ethereum.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/ethereum.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec. It's available on npm as a node module, for bower and component as an embeddable js and as a meteor.js package.
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url]
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url][![Stories in Ready][waffle-image]][waffle-url]
<!-- [![browser support](https://ci.testling.com/ethereum/ethereum.js.png)](https://ci.testling.com/ethereum/ethereum.js) -->
@ -36,7 +38,7 @@ Component
## Usage
Require the library (not required for the meteor package):
var web3 = require('web3');
var web3 = require('ethereum.js');
Set a provider (QtSyncProvider, HttpProvider)
@ -110,4 +112,6 @@ eth -j
[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies
[coveralls-image]: https://coveralls.io/repos/ethereum/ethereum.js/badge.svg?branch=master
[coveralls-url]: https://coveralls.io/r/ethereum/ethereum.js?branch=master
[waffle-image]: https://badge.waffle.io/ethereum/ethereum.js.svg?label=ready&title=Ready
[waffle-url]: http://waffle.io/ethereum/ethereum.js

4
bower.json

@ -1,7 +1,7 @@
{
"name": "ethereum.js",
"name": "web3",
"namespace": "ethereum",
"version": "0.1.2",
"version": "0.2.5",
"description": "Ethereum Compatible JavaScript API",
"main": [
"./dist/ethereum.js",

57
dist/ethereum.js.map

File diff suppressed because one or more lines are too long

1
dist/ethereum.min.js

File diff suppressed because one or more lines are too long

1885
dist/ethereum.js → dist/web3-light.js

File diff suppressed because it is too large

69
dist/web3-light.js.map

File diff suppressed because one or more lines are too long

1
dist/web3-light.min.js

File diff suppressed because one or more lines are too long

5921
dist/web3.js

File diff suppressed because it is too large

69
dist/web3.js.map

File diff suppressed because one or more lines are too long

2
dist/web3.min.js

File diff suppressed because one or more lines are too long

4
example/balance.html

@ -2,8 +2,8 @@
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../node_modules/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/web3-light.js"></script>
<script type="text/javascript">
var web3 = require('web3');

3
example/contract.html

@ -2,8 +2,7 @@
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../dist/web3"></script>
<script type="text/javascript">
var web3 = require('web3');

3
example/contract_with_array.html

@ -2,8 +2,7 @@
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript">
var web3 = require('web3');

3
example/event.html

@ -1,8 +1,7 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8080'));

3
example/event_inc.html

@ -1,8 +1,7 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8080'));

3
example/natspec_contract.html

@ -2,8 +2,7 @@
<html>
<head>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../dist/web3.js"></script>
<script type="text/javascript">
var web3 = require('web3');

34
gulpfile.js

@ -2,7 +2,7 @@
'use strict';
var version = require('./version.json');
var version = require('./lib/version.json');
var path = require('path');
var del = require('del');
@ -19,19 +19,23 @@ var replace = require('gulp-replace');
var DEST = './dist/';
var src = 'index';
var dst = 'ethereum';
var dst = 'web3';
var lightDst = 'web3-light';
var browserifyOptions = {
debug: true,
insert_global_vars: false, // jshint ignore:line
detectGlobals: false,
bundleExternal: false
bundleExternal: true
};
gulp.task('versionReplace', function(){
gulp.src(['./package.json'])
.pipe(replace(/\"version\"\: \"(.{5})\"/, '"version": "'+ version.version + '"'))
.pipe(gulp.dest('./'));
gulp.src(['./bower.json'])
.pipe(replace(/\"version\"\: \"(.{5})\"/, '"version": "'+ version.version + '"'))
.pipe(gulp.dest('./'));
gulp.src(['./package.js'])
.pipe(replace(/version\: \'(.{5})\'/, "version: '"+ version.version + "'"))
.pipe(gulp.dest('./'));
@ -54,10 +58,27 @@ gulp.task('lint', function(){
.pipe(jshint.reporter('default'));
});
gulp.task('build', ['clean'], function () {
gulp.task('buildLight', ['clean'], function () {
return browserify(browserifyOptions)
.require('./' + src + '.js', {expose: 'web3'})
.ignore('bignumber.js')
.require('./lib/utils/browser-bn.js', {expose: 'bignumber.js'}) // fake bignumber.js
.add('./' + src + '.js')
.bundle()
.pipe(exorcist(path.join( DEST, lightDst + '.js.map')))
.pipe(source(lightDst + '.js'))
.pipe(gulp.dest( DEST ))
.pipe(streamify(uglify()))
.pipe(rename(lightDst + '.min.js'))
.pipe(gulp.dest( DEST ));
});
gulp.task('buildStandalone', ['clean'], function () {
return browserify(browserifyOptions)
.require('./' + src + '.js', {expose: 'web3'})
.require('bignumber.js') // expose it to dapp users
.add('./' + src + '.js')
.ignore('crypto')
.bundle()
.pipe(exorcist(path.join( DEST, dst + '.js.map')))
.pipe(source(dst + '.js'))
@ -71,8 +92,9 @@ gulp.task('watch', function() {
gulp.watch(['./lib/*.js'], ['lint', 'build']);
});
gulp.task('dev', ['versionReplace','bower', 'lint', 'build']);
gulp.task('default', ['dev']);
gulp.task('light', ['versionReplace','bower', 'lint', 'buildLight']);
gulp.task('standalone', ['versionReplace','bower', 'lint', 'buildStandalone']);
gulp.task('default', ['light', 'standalone']);
gulp.task('version', ['versionReplace']);

9
index.js

@ -1,7 +1,14 @@
var web3 = require('./lib/web3');
// dont override global variable
if (typeof web3 !== 'undefined') {
var web3;
}
web3 = require('./lib/web3');
web3.providers.HttpProvider = require('./lib/web3/httpprovider');
web3.providers.QtSyncProvider = require('./lib/web3/qtsync');
web3.eth.contract = require('./lib/web3/contract');
web3.abi = require('./lib/solidity/abi');
module.exports = web3;

3
karma.conf.js

@ -22,8 +22,7 @@ module.exports = function (config) {
// list of files / patterns to load in the browser
files: [
'node_modules/bignumber.js/bignumber.js',
'test/*.js',
'test/*.js'
],

20
lib/solidity/formatters.js

@ -20,26 +20,10 @@
* @date 2015
*/
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var BigNumber = require('bignumber.js');
var utils = require('../utils/utils');
var c = require('../utils/config');
/**
* Should be called to pad string to expected length
*
* @method padLeft
* @param {String} string to be padded
* @param {Number} characters that result string should have
* @param {String} sign, by default 0
* @returns {String} right aligned string
*/
var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
};
/**
* Formats input value to byte representation of int
* If value is negative, return it's two's complement
@ -52,7 +36,7 @@ var padLeft = function (string, chars, sign) {
var formatInputInt = function (value) {
var padding = c.ETH_PADDING * 2;
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
return padLeft(utils.toTwosComplement(value).round().toString(16), padding);
return utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);
};
/**

4
lib/utils/browser-bn.js

@ -0,0 +1,4 @@
'use strict';
module.exports = BigNumber; // jshint ignore:line

9
lib/utils/browser-xhr.js

@ -0,0 +1,9 @@
'use strict';
// go env doesn't have and need XMLHttpRequest
if (typeof XMLHttpRequest === 'undefined') {
exports.XMLHttpRequest = {};
} else {
exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line
}

4
lib/utils/config.js

@ -34,9 +34,7 @@
*/
/// required to define ETH_BIGNUMBER_ROUNDING_MODE
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var BigNumber = require('bignumber.js');
var ETH_UNITS = [
'wei',

68
lib/utils/utils.js

@ -33,9 +33,7 @@
* @constructor
*/
if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var BigNumber = require('bignumber.js');
var unitMap = {
'wei': '1',
@ -56,6 +54,18 @@ var unitMap = {
'tether': '1000000000000000000000000000000'
};
/**
* Should be called to pad string to expected length
*
* @method padLeft
* @param {String} string to be padded
* @param {Number} characters that result string should have
* @param {String} sign, by default 0
* @returns {String} right aligned string
*/
var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
};
/** Finds first index of array element matching pattern
*
@ -214,13 +224,13 @@ var fromDecimal = function (value) {
var toHex = function (val) {
/*jshint maxcomplexity:7 */
if(isBoolean(val))
return val;
if (isBoolean(val))
return fromDecimal(+val);
if(isBigNumber(val))
if (isBigNumber(val))
return fromDecimal(val);
if(isObject(val))
if (isObject(val))
return fromAscii(JSON.stringify(val));
// if its a negative number, pass it through fromDecimal
@ -345,13 +355,27 @@ var toTwosComplement = function (number) {
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isAddress = function(address) {
if (!isString(address)) {
return false;
var isAddress = function (address) {
return /^0x[0-9a-f]{40}$/.test(address);
};
/**
* Transforms given string to valid 20 bytes-length addres with 0x prefix
*
* @method toAddress
* @param {String} address
* @return {String} formatted address
*/
var toAddress = function (address) {
if (isAddress(address)) {
return address;
}
return ((address.indexOf('0x') === 0 && address.length === 42) ||
(address.indexOf('0x') === -1 && address.length === 40));
if (/^[0-9a-f]{40}$/.test(address)) {
return '0x' + address;
}
return '0x' + padLeft(toHex(address).substr(2), 40);
};
/**
@ -422,7 +446,23 @@ var isArray = function (object) {
return object instanceof Array;
};
/**
* Returns true if given string is valid json object
*
* @method isJson
* @param {String}
* @return {Boolean}
*/
var isJson = function (str) {
try {
return !!JSON.parse(str);
} catch (e) {
return false;
}
};
module.exports = {
padLeft: padLeft,
findIndex: findIndex,
toHex: toHex,
toDecimal: toDecimal,
@ -437,12 +477,14 @@ module.exports = {
fromWei: fromWei,
toBigNumber: toBigNumber,
toTwosComplement: toTwosComplement,
toAddress: toAddress,
isBigNumber: isBigNumber,
isAddress: isAddress,
isFunction: isFunction,
isString: isString,
isObject: isObject,
isBoolean: isBoolean,
isArray: isArray
isArray: isArray,
isJson: isJson
};

3
lib/version.json

@ -0,0 +1,3 @@
{
"version": "0.2.5"
}

288
lib/web3.js

@ -24,79 +24,55 @@
* @date 2014
*/
var version = require('../version.json');
var version = require('./version.json');
var net = require('./web3/net');
var eth = require('./web3/eth');
var db = require('./web3/db');
var shh = require('./web3/shh');
var watches = require('./web3/watches');
var filter = require('./web3/filter');
var Filter = require('./web3/filter');
var utils = require('./utils/utils');
var formatters = require('./solidity/formatters');
var requestManager = require('./web3/requestmanager');
var formatters = require('./web3/formatters');
var RequestManager = require('./web3/requestmanager');
var c = require('./utils/config');
var Method = require('./web3/method');
var Property = require('./web3/property');
/// @returns an array of objects describing web3 api methods
var web3Methods = [
{ name: 'sha3', call: 'web3_sha3', inputFormatter: utils.toHex },
new Method({
name: 'sha3',
call: 'web3_sha3',
params: 1
})
];
var web3Properties = [
{ name: 'version.client', getter: 'web3_clientVersion' },
{ name: 'version.network', getter: 'net_version' }
new Property({
name: 'version.client',
getter: 'web3_clientVersion'
}),
new Property({
name: 'version.network',
getter: 'net_version',
inputFormatter: utils.toDecimal
}),
new Property({
name: 'version.ethereum',
getter: 'eth_version',
inputFormatter: utils.toDecimal
}),
new Property({
name: 'version.whisper',
getter: 'shh_version',
inputFormatter: utils.toDecimal
})
];
/// creates methods in a given object based on method description on input
/// setups api calls for these methods
var setupMethods = function (obj, methods) {
methods.forEach(function (method) {
// allow for object methods 'myObject.method'
var objectMethods = method.name.split('.'),
callFunction = function () {
/*jshint maxcomplexity:8 */
var callback = null,
args = Array.prototype.slice.call(arguments),
call = typeof method.call === 'function' ? method.call(args) : method.call;
// get the callback if one is available
if(typeof args[args.length-1] === 'function'){
callback = args[args.length-1];
Array.prototype.pop.call(args);
}
// add the defaultBlock if not given
if(method.addDefaultblock) {
if(args.length !== method.addDefaultblock)
Array.prototype.push.call(args, (isFinite(c.ETH_DEFAULTBLOCK) ? utils.fromDecimal(c.ETH_DEFAULTBLOCK) : c.ETH_DEFAULTBLOCK));
else
args[args.length-1] = isFinite(args[args.length-1]) ? utils.fromDecimal(args[args.length-1]) : args[args.length-1];
}
// show deprecated warning
if(method.newMethod)
console.warn('This method is deprecated please use web3.'+ method.newMethod +'() instead.');
return web3.manager.send({
method: call,
params: args,
outputFormatter: method.outputFormatter,
inputFormatter: method.inputFormatter,
addDefaultblock: method.addDefaultblock
}, callback);
};
if(objectMethods.length > 1) {
if(!obj[objectMethods[0]])
obj[objectMethods[0]] = {};
obj[objectMethods[0]][objectMethods[1]] = callFunction;
} else {
obj[objectMethods[0]] = callFunction;
}
method.attachToObject(obj);
});
};
@ -104,173 +80,53 @@ var setupMethods = function (obj, methods) {
/// setups api calls for these properties
var setupProperties = function (obj, properties) {
properties.forEach(function (property) {
var objectProperties = property.name.split('.'),
proto = {};
proto.get = function () {
// show deprecated warning
if(property.newProperty)
console.warn('This property is deprecated please use web3.'+ property.newProperty +' instead.');
return web3.manager.send({
method: property.getter,
outputFormatter: property.outputFormatter
});
};
if (property.setter) {
proto.set = function (val) {
// show deprecated warning
if(property.newProperty)
console.warn('This property is deprecated please use web3.'+ property.newProperty +' instead.');
return web3.manager.send({
method: property.setter,
params: [val],
inputFormatter: property.inputFormatter
});
};
}
proto.enumerable = !property.newProperty;
if(objectProperties.length > 1) {
if(!obj[objectProperties[0]])
obj[objectProperties[0]] = {};
Object.defineProperty(obj[objectProperties[0]], objectProperties[1], proto);
} else
Object.defineProperty(obj, property.name, proto);
property.attachToObject(obj);
});
};
/// setups web3 object, and it's in-browser executed methods
var web3 = {};
web3.providers = {};
web3.version = {};
web3.version.api = version.version;
web3.eth = {};
/*jshint maxparams:4 */
var startPolling = function (method, id, callback, uninstall) {
web3.manager.startPolling({
method: method,
params: [id]
}, id, callback, uninstall);
};
/*jshint maxparams:3 */
web3.eth.filter = function (fil, eventParams, options, formatter) {
var stopPolling = function (id) {
web3.manager.stopPolling(id);
};
// if its event, treat it differently
// TODO: simplify and remove
if (fil._isEvent) {
return fil(eventParams, options);
}
var ethWatch = {
startPolling: startPolling.bind(null, 'eth_getFilterChanges'),
stopPolling: stopPolling
// what outputLogFormatter? that's wrong
//return new Filter(fil, watches.eth(), formatters.outputLogFormatter);
return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);
};
/*jshint maxparams:3 */
var shhWatch = {
startPolling: startPolling.bind(null, 'shh_getFilterChanges'),
stopPolling: stopPolling
web3.shh = {};
web3.shh.filter = function (fil) {
return new Filter(fil, watches.shh(), formatters.outputPostFormatter);
};
/// setups web3 object, and it's in-browser executed methods
var web3 = {
version: {
api: version.version
},
manager: requestManager(),
providers: {},
setProvider: function (provider) {
web3.manager.setProvider(provider);
},
/// Should be called to reset state of web3 object
/// Resets everything except manager
reset: function () {
web3.manager.reset();
},
/// @returns hex string of the input
toHex: utils.toHex,
/// @returns ascii string representation of hex value prefixed with 0x
toAscii: utils.toAscii,
/// @returns hex representation (prefixed by 0x) of ascii string
fromAscii: utils.fromAscii,
/// @returns decimal representaton of hex value prefixed by 0x
toDecimal: utils.toDecimal,
/// @returns hex representation (prefixed by 0x) of decimal value
fromDecimal: utils.fromDecimal,
/// @returns a BigNumber object
toBigNumber: utils.toBigNumber,
toWei: utils.toWei,
fromWei: utils.fromWei,
isAddress: utils.isAddress,
// provide network information
net: {
// peerCount:
},
/// eth object prototype
eth: {
// DEPRECATED
contractFromAbi: function (abi) {
console.warn('Initiating a contract like this is deprecated please use var MyContract = eth.contract(abi); new MyContract(address); instead.');
return function(addr) {
// Default to address of Config. TODO: rremove prior to genesis.
addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';
var ret = web3.eth.contract(addr, abi);
ret.address = addr;
return ret;
};
},
/// @param filter may be a string, object or event
/// @param eventParams is optional, this is an object with optional event eventParams params
/// @param options is optional, this is an object with optional event options ('max'...)
/*jshint maxparams:4 */
filter: function (fil, eventParams, options) {
// if its event, treat it differently
if (fil._isEvent)
return fil(eventParams, options);
return filter(fil, ethWatch, formatters.outputLogFormatter);
},
// DEPRECATED
watch: function (fil, eventParams, options) {
console.warn('eth.watch() is deprecated please use eth.filter() instead.');
return this.filter(fil, eventParams, options);
}
/*jshint maxparams:3 */
},
/// db object prototype
db: {},
/// shh object prototype
shh: {
/// @param filter may be a string, object or event
filter: function (fil) {
return filter(fil, shhWatch, formatters.outputPostFormatter);
},
// DEPRECATED
watch: function (fil) {
console.warn('shh.watch() is deprecated please use shh.filter() instead.');
return this.filter(fil);
}
}
web3.net = {};
web3.db = {};
web3.setProvider = function (provider) {
RequestManager.getInstance().setProvider(provider);
};
web3.reset = function () {
RequestManager.getInstance().reset();
};
web3.toHex = utils.toHex;
web3.toAscii = utils.toAscii;
web3.fromAscii = utils.fromAscii;
web3.toDecimal = utils.toDecimal;
web3.fromDecimal = utils.fromDecimal;
web3.toBigNumber = utils.toBigNumber;
web3.toWei = utils.toWei;
web3.fromWei = utils.fromWei;
web3.isAddress = utils.isAddress;
// ADD defaultblock
Object.defineProperty(web3.eth, 'defaultBlock', {
@ -291,10 +147,8 @@ setupMethods(web3.net, net.methods);
setupProperties(web3.net, net.properties);
setupMethods(web3.eth, eth.methods);
setupProperties(web3.eth, eth.properties);
setupMethods(web3.db, db.methods());
setupMethods(web3.shh, shh.methods());
setupMethods(ethWatch, watches.eth());
setupMethods(shhWatch, watches.shh());
setupMethods(web3.db, db.methods);
setupMethods(web3.shh, shh.methods);
module.exports = web3;

45
lib/web3/contract.js

@ -26,15 +26,6 @@ var utils = require('../utils/utils');
var eventImpl = require('./event');
var signature = require('./signature');
var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js
// TODO: figure out better way to solve this
web3._currentContractAbi = vars.abi;
web3._currentContractAddress = vars.address;
web3._currentContractMethodName = vars.method;
web3._currentContractMethodParams = vars.params;
};
var addFunctionRelatedPropertiesToContract = function (contract) {
contract.call = function (options) {
@ -43,28 +34,11 @@ var addFunctionRelatedPropertiesToContract = function (contract) {
return contract;
};
contract.sendTransaction = function (options) {
contract._isTransaction = true;
contract._options = options;
return contract;
};
// DEPRECATED
contract.transact = function (options) {
console.warn('myContract.transact() is deprecated please use myContract.sendTransaction() instead.');
return contract.sendTransaction(options);
};
contract._options = {};
['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {
contract[p] = function (v) {
contract._options[p] = v;
return contract;
};
});
};
var addFunctionsToContract = function (contract, desc, address) {
@ -96,13 +70,6 @@ var addFunctionsToContract = function (contract, desc, address) {
if (isTransaction) {
exportNatspecGlobals({
abi: desc,
address: address,
method: method.name,
params: params
});
// transactions do not have any output, cause we do not know, when they will be processed
web3.eth.sendTransaction(options);
return;
@ -203,17 +170,7 @@ var addEventsToContract = function (contract, desc, address) {
var contract = function (abi) {
// return prototype
if(abi instanceof Array && arguments.length === 1) {
return Contract.bind(null, abi);
// deprecated: auto initiate contract
} else {
console.warn('Initiating a contract like this is deprecated please use var MyContract = eth.contract(abi); new MyContract(address); instead.');
return new Contract(arguments[1], arguments[0]);
}
return Contract.bind(null, abi);
};
function Contract(abi, address) {

38
lib/web3/db.js

@ -20,16 +20,36 @@
* @date 2015
*/
var Method = require('./method');
/// @returns an array of objects describing web3.db api methods
var methods = function () {
return [
{ name: 'putString', call: 'db_putString'},
{ name: 'getString', call: 'db_getString'},
{ name: 'putHex', call: 'db_putHex'},
{ name: 'getHex', call: 'db_getHex'}
];
};
var putString = new Method({
name: 'putString',
call: 'db_putString',
params: 3
});
var getString = new Method({
name: 'getString',
call: 'db_getString',
params: 2
});
var putHex = new Method({
name: 'putHex',
call: 'db_putHex',
params: 3
});
var getHex = new Method({
name: 'getHex',
call: 'db_getHex',
params: 2
});
var methods = [
putString, getString, putHex, getHex
];
module.exports = {
methods: methods

38
lib/web3/errors.js

@ -0,0 +1,38 @@
/*
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 errors.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var utils = require('../utils/utils');
module.exports = {
InvalidNumberOfParams: new Error('Invalid number of input parameters'),
InvalidProvider: new Error('Providor not set or invalid'),
InvalidResponse: function(result){
var message = 'Invalid JSON RPC response';
if(utils.isObject(result) && result.error && result.error.message) {
message = result.error.message;
}
return new Error(message);
}
};

243
lib/web3/eth.js

@ -14,10 +14,10 @@
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 eth.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
/**
* @file eth.js
* @author Marek Kotewicz <marek@ethdev.com>
* @author Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
@ -35,10 +35,11 @@
* {
* name: 'getBlock',
* call: blockCall,
* params: 2,
* outputFormatter: formatters.outputBlockFormatter,
* inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter
* utils.toHex, // formats paramter 1
* function(param){ if(!param) return false; } // formats paramter 2
* function(param){ return !!param; } // formats paramter 2
* ]
* },
*
@ -46,10 +47,12 @@
* @constructor
*/
"use strict";
var formatters = require('./formatters');
var utils = require('../utils/utils');
var Method = require('./method');
var Property = require('./property');
var blockCall = function (args) {
return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber";
@ -72,76 +75,178 @@ var uncleCountCall = function (args) {
};
/// @returns an array of objects describing web3.eth api methods
var getBalance = new Method({
name: 'getBalance',
call: 'eth_getBalance',
params: 2,
inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: formatters.outputBigNumberFormatter
});
var getStorageAt = new Method({
name: 'getStorageAt',
call: 'eth_getStorageAt',
params: 3,
inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]
});
var getCode = new Method({
name: 'getCode',
call: 'eth_getCode',
params: 2,
inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]
});
var getBlock = new Method({
name: 'getBlock',
call: blockCall,
params: 2,
inputFormatter: [utils.toHex, function (val) { return !!val; }],
outputFormatter: formatters.outputBlockFormatter
});
var getUncle = new Method({
name: 'getUncle',
call: uncleCall,
params: 3,
inputFormatter: [utils.toHex, utils.toHex, function (val) { return !!val; }],
outputFormatter: formatters.outputBlockFormatter,
});
var getCompilers = new Method({
name: 'getCompilers',
call: 'eth_getCompilers',
params: 0
});
var getBlockTransactionCount = new Method({
name: 'getBlockTransactionCount',
call: getBlockTransactionCountCall,
params: 1,
inputFormatter: [formatters.inputBlockNumberFormatter],
outputFormatter: utils.toDecimal
});
var getBlockUncleCount = new Method({
name: 'getBlockUncleCount',
call: uncleCountCall,
params: 1,
inputFormatter: [formatters.inputBlockNumberFormatter],
outputFormatter: utils.toDecimal
});
var getTransaction = new Method({
name: 'getTransaction',
call: 'eth_getTransactionByHash',
params: 1,
outputFormatter: formatters.outputTransactionFormatter
});
var getTransactionFromBlock = new Method({
name: 'getTransactionFromBlock',
call: transactionFromBlockCall,
params: 2,
inputFormatter: [utils.toHex, utils.toHex],
outputFormatter: formatters.outputTransactionFormatter
});
var getTransactionCount = new Method({
name: 'getTransactionCount',
call: 'eth_getTransactionCount',
params: 2,
inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],
outputFormatter: utils.toDecimal
});
var sendTransaction = new Method({
name: 'sendTransaction',
call: 'eth_sendTransaction',
params: 1,
inputFormatter: [formatters.inputTransactionFormatter]
});
var call = new Method({
name: 'call',
call: 'eth_call',
params: 2,
inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]
});
var compileSolidity = new Method({
name: 'compile.solidity',
call: 'eth_compileSolidity',
params: 1
});
var compileLLL = new Method({
name: 'compile.lll',
call: 'eth_compileLLL',
params: 1
});
var compileSerpent = new Method({
name: 'compile.serpent',
call: 'eth_compileSerpent',
params: 1
});
var flush = new Method({
name: 'flush',
call: 'eth_flush',
params: 0
});
var methods = [
{ name: 'getBalance', call: 'eth_getBalance', addDefaultblock: 2,
outputFormatter: formatters.convertToBigNumber},
{ name: 'getStorage', call: 'eth_getStorage', addDefaultblock: 2},
{ name: 'getStorageAt', call: 'eth_getStorageAt', addDefaultblock: 3,
inputFormatter: utils.toHex},
{ name: 'getData', call: 'eth_getData', addDefaultblock: 2},
{ name: 'getBlock', call: blockCall,
outputFormatter: formatters.outputBlockFormatter,
inputFormatter: [utils.toHex, function(param){ return (!param) ? false : true; }]},
{ name: 'getUncle', call: uncleCall,
outputFormatter: formatters.outputBlockFormatter,
inputFormatter: [utils.toHex, utils.toHex, function(param){ return (!param) ? false : true; }]},
{ name: 'getCompilers', call: 'eth_getCompilers' },
{ name: 'getBlockTransactionCount', call: getBlockTransactionCountCall,
outputFormatter: utils.toDecimal,
inputFormatter: utils.toHex },
{ name: 'getBlockUncleCount', call: uncleCountCall,
outputFormatter: utils.toDecimal,
inputFormatter: utils.toHex },
{ name: 'getTransaction', call: 'eth_getTransactionByHash',
outputFormatter: formatters.outputTransactionFormatter },
{ name: 'getTransactionFromBlock', call: transactionFromBlockCall,
outputFormatter: formatters.outputTransactionFormatter,
inputFormatter: utils.toHex },
{ name: 'getTransactionCount', call: 'eth_getTransactionCount', addDefaultblock: 2,
outputFormatter: utils.toDecimal},
{ name: 'sendTransaction', call: 'eth_sendTransaction',
inputFormatter: formatters.inputTransactionFormatter },
{ name: 'call', call: 'eth_call', addDefaultblock: 2,
inputFormatter: formatters.inputCallFormatter },
{ name: 'compile.solidity', call: 'eth_compileSolidity' },
{ name: 'compile.lll', call: 'eth_compileLLL', inputFormatter: utils.toHex },
{ name: 'compile.serpent', call: 'eth_compileSerpent', inputFormatter: utils.toHex },
{ name: 'flush', call: 'eth_flush' },
// deprecated methods
{ name: 'balanceAt', call: 'eth_balanceAt', newMethod: 'eth.getBalance' },
{ name: 'stateAt', call: 'eth_stateAt', newMethod: 'eth.getStorageAt' },
{ name: 'storageAt', call: 'eth_storageAt', newMethod: 'eth.getStorage' },
{ name: 'countAt', call: 'eth_countAt', newMethod: 'eth.getTransactionCount' },
{ name: 'codeAt', call: 'eth_codeAt', newMethod: 'eth.getData' },
{ name: 'transact', call: 'eth_transact', newMethod: 'eth.sendTransaction' },
{ name: 'block', call: blockCall, newMethod: 'eth.getBlock' },
{ name: 'transaction', call: transactionFromBlockCall, newMethod: 'eth.getTransaction' },
{ name: 'uncle', call: uncleCall, newMethod: 'eth.getUncle' },
{ name: 'compilers', call: 'eth_compilers', newMethod: 'eth.getCompilers' },
{ name: 'solidity', call: 'eth_solidity', newMethod: 'eth.compile.solidity' },
{ name: 'lll', call: 'eth_lll', newMethod: 'eth.compile.lll' },
{ name: 'serpent', call: 'eth_serpent', newMethod: 'eth.compile.serpent' },
{ name: 'transactionCount', call: getBlockTransactionCountCall, newMethod: 'eth.getBlockTransactionCount' },
{ name: 'uncleCount', call: uncleCountCall, newMethod: 'eth.getBlockUncleCount' },
{ name: 'logs', call: 'eth_logs' }
getBalance,
getStorageAt,
getCode,
getBlock,
getUncle,
getCompilers,
getBlockTransactionCount,
getBlockUncleCount,
getTransaction,
getTransactionFromBlock,
getTransactionCount,
call,
sendTransaction,
compileSolidity,
compileLLL,
compileSerpent,
flush
];
/// @returns an array of objects describing web3.eth api properties
var properties = [
{ name: 'coinbase', getter: 'eth_coinbase'},
{ name: 'mining', getter: 'eth_mining'},
{ name: 'gasPrice', getter: 'eth_gasPrice', outputFormatter: formatters.convertToBigNumber},
{ name: 'accounts', getter: 'eth_accounts' },
{ name: 'blockNumber', getter: 'eth_blockNumber', outputFormatter: utils.toDecimal},
// deprecated properties
{ name: 'listening', getter: 'net_listening', setter: 'eth_setListening', newProperty: 'net.listening'},
{ name: 'peerCount', getter: 'net_peerCount', newProperty: 'net.peerCount'},
{ name: 'number', getter: 'eth_number', newProperty: 'eth.blockNumber'}
new Property({
name: 'coinbase',
getter: 'eth_coinbase'
}),
new Property({
name: 'mining',
getter: 'eth_mining'
}),
new Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: formatters.inputNumberFormatter
}),
new Property({
name: 'accounts',
getter: 'eth_accounts'
}),
new Property({
name: 'blockNumber',
getter: 'eth_blockNumber',
outputFormatter: utils.toDecimal
})
];
module.exports = {
methods: methods,
properties: properties

4
lib/web3/event.js

@ -57,7 +57,7 @@ var indexedParamsToTopics = function (event, indexed) {
return abi.formatInput(inputs, [v]);
});
}
return abi.formatInput(inputs, [value]);
return '0x' + abi.formatInput(inputs, [value]);
});
};
@ -101,10 +101,10 @@ var outputParser = function (event) {
args: {}
};
output.topics = output.topic; // fallback for go-ethereum
if (!output.topics) {
return result;
}
output.data = output.data || '';
var indexedOutputs = filterInputs(event.inputs, true);
var indexedData = "0x" + output.topics.slice(1, output.topics.length).map(function (topics) { return topics.slice(2); }).join("");

170
lib/web3/filter.js

@ -24,153 +24,87 @@
* @date 2014
*/
var RequestManager = require('./requestmanager');
var formatters = require('./formatters');
var utils = require('../utils/utils');
/// Should be called to check if filter implementation is valid
/// @returns true if it is, otherwise false
var implementationIsValid = function (i) {
return !!i &&
typeof i.newFilter === 'function' &&
typeof i.getLogs === 'function' &&
typeof i.uninstallFilter === 'function' &&
typeof i.startPolling === 'function' &&
typeof i.stopPolling === 'function';
};
/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones
/// @param should be string or object
/// @returns options string or object
var getOptions = function (options) {
/*jshint maxcomplexity:9 */
if (typeof options === 'string') {
if (utils.isString(options)) {
return options;
}
options = options || {};
if (options.topic) {
console.warn('"topic" is deprecated, is "topics" instead');
options.topics = options.topic;
}
if (options.earliest) {
console.warn('"earliest" is deprecated, is "fromBlock" instead');
options.fromBlock = options.earliest;
}
if (options.latest) {
console.warn('"latest" is deprecated, is "toBlock" instead');
options.toBlock = options.latest;
}
if (options.skip) {
console.warn('"skip" is deprecated, is "offset" instead');
options.offset = options.skip;
}
if (options.max) {
console.warn('"max" is deprecated, is "limit" instead');
options.limit = options.max;
}
// make sure topics, get converted to hex
if(options.topics instanceof Array) {
options.topics = options.topics.map(function(topic){
return utils.toHex(topic);
});
}
options.topics = options.topics || [];
options.topics = options.topics.map(function(topic){
return utils.toHex(topic);
});
// evaluate lazy properties
// lazy load
return {
fromBlock: utils.toHex(options.fromBlock),
toBlock: utils.toHex(options.toBlock),
limit: utils.toHex(options.limit),
offset: utils.toHex(options.offset),
topics: options.topics,
to: options.to,
address: options.address,
topics: options.topics
fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),
toBlock: formatters.inputBlockNumberFormatter(options.toBlock)
};
};
/// Should be used when we want to watch something
/// it's using inner polling mechanism and is notified about changes
/// @param options are filter options
/// @param implementation, an abstract polling implementation
/// @param formatter (optional), callback function which formats output before 'real' callback
var filter = function(options, implementation, formatter) {
if (!implementationIsValid(implementation)) {
console.error('filter implemenation is invalid');
return;
}
var Filter = function (options, methods, formatter) {
var implementation = {};
methods.forEach(function (method) {
method.attachToObject(implementation);
});
this.options = getOptions(options);
this.implementation = implementation;
this.callbacks = [];
this.formatter = formatter;
this.filterId = this.implementation.newFilter(this.options);
};
Filter.prototype.watch = function (callback) {
this.callbacks.push(callback);
var self = this;
options = getOptions(options);
var callbacks = [];
var filterId = implementation.newFilter(options);
var onMessage = function (error, messages) {
if (error) {
return self.callbacks.forEach(function (callback) {
callback(error);
});
}
// call the callbacks
var onMessages = function (messages) {
messages.forEach(function (message) {
message = formatter ? formatter(message) : message;
callbacks.forEach(function (callback) {
callback(message);
message = self.formatter ? self.formatter(message) : message;
self.callbacks.forEach(function (callback) {
callback(null, message);
});
});
};
implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);
var watch = function(callback) {
callbacks.push(callback);
};
var stopWatching = function() {
implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId);
callbacks = [];
};
var get = function () {
var results = implementation.getLogs(filterId);
RequestManager.getInstance().startPolling({
method: this.implementation.poll.call,
params: [this.filterId],
}, this.filterId, onMessage, this.stopWatching.bind(this));
};
return utils.isArray(results) ? results.map(function(message){
return formatter ? formatter(message) : message;
}) : results;
};
Filter.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.filterId);
this.implementation.uninstallFilter(this.filterId);
this.callbacks = [];
};
return {
watch: watch,
stopWatching: stopWatching,
get: get,
// DEPRECATED methods
changed: function(){
console.warn('watch().changed() is deprecated please use filter().watch() instead.');
return watch.apply(this, arguments);
},
arrived: function(){
console.warn('watch().arrived() is deprecated please use filter().watch() instead.');
return watch.apply(this, arguments);
},
happened: function(){
console.warn('watch().happened() is deprecated please use filter().watch() instead.');
return watch.apply(this, arguments);
},
uninstall: function(){
console.warn('watch().uninstall() is deprecated please use filter().stopWatching() instead.');
return stopWatching.apply(this, arguments);
},
messages: function(){
console.warn('watch().messages() is deprecated please use filter().get() instead.');
return get.apply(this, arguments);
},
logs: function(){
console.warn('watch().logs() is deprecated please use filter().get() instead.');
return get.apply(this, arguments);
}
};
Filter.prototype.get = function () {
var logs = this.implementation.getLogs(this.filterId);
var self = this;
return logs.map(function (log) {
return self.formatter ? self.formatter(log) : log;
});
};
module.exports = filter;
module.exports = Filter;

92
lib/web3/formatters.js

@ -14,24 +14,45 @@
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 formatters.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
/**
* @file formatters.js
* @author Marek Kotewicz <marek@ethdev.com>
* @author Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
var utils = require('../utils/utils');
var config = require('../utils/config');
/**
* Should the input to a big number
* Should the format output to a big number
*
* @method convertToBigNumber
* @method outputBigNumberFormatter
* @param {String|Number|BigNumber}
* @returns {BigNumber} object
*/
var convertToBigNumber = function (value) {
return utils.toBigNumber(value);
var outputBigNumberFormatter = function (number) {
return utils.toBigNumber(number);
};
var isPredefinedBlockNumber = function (blockNumber) {
return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';
};
var inputDefaultBlockNumberFormatter = function (blockNumber) {
if (blockNumber === undefined) {
return config.ETH_DEFAULTBLOCK;
}
return inputBlockNumberFormatter(blockNumber);
};
var inputBlockNumberFormatter = function (blockNumber) {
if (blockNumber === undefined) {
return undefined;
} else if (isPredefinedBlockNumber(blockNumber)) {
return blockNumber;
}
return utils.toHex(blockNumber);
};
/**
@ -49,7 +70,9 @@ var inputTransactionFormatter = function (options){
delete options.code;
}
['gasPrice', 'gas', 'value'].forEach(function(key){
['gasPrice', 'gas', 'value'].filter(function (key) {
return options[key] !== undefined;
}).forEach(function(key){
options[key] = utils.fromDecimal(options[key]);
});
@ -64,31 +87,14 @@ var inputTransactionFormatter = function (options){
* @returns {Object} transaction
*/
var outputTransactionFormatter = function (tx){
tx.blockNumber = utils.toDecimal(tx.blockNumber);
tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.gas = utils.toDecimal(tx.gas);
tx.gasPrice = utils.toBigNumber(tx.gasPrice);
tx.value = utils.toBigNumber(tx.value);
return tx;
};
/**
* Formats the input of a call and converts all values to HEX
*
* @method inputCallFormatter
* @param {Object} transaction options
* @returns object
*/
var inputCallFormatter = function (options){
// make code -> data
if (options.code) {
options.data = options.code;
delete options.code;
}
return options;
};
/**
* Formats the output of a block to its proper values
*
@ -96,7 +102,7 @@ var inputCallFormatter = function (options){
* @param {Object} block object
* @returns {Object} block object
*/
var outputBlockFormatter = function(block){
var outputBlockFormatter = function(block) {
// transform to number
block.gasLimit = utils.toDecimal(block.gasLimit);
@ -109,7 +115,7 @@ var outputBlockFormatter = function(block){
block.difficulty = utils.toBigNumber(block.difficulty);
block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
if(block.transactions instanceof Array) {
if (utils.isArray(block.transactions)) {
block.transactions.forEach(function(item){
if(!utils.isString(item))
return outputTransactionFormatter(item);
@ -126,7 +132,11 @@ var outputBlockFormatter = function(block){
* @param {Object} log object
* @returns {Object} log
*/
var outputLogFormatter = function(log){
var outputLogFormatter = function(log) {
if (log === null) { // 'pending' && 'latest' filters are nulls
return null;
}
log.blockNumber = utils.toDecimal(log.blockNumber);
log.transactionIndex = utils.toDecimal(log.transactionIndex);
log.logIndex = utils.toDecimal(log.logIndex);
@ -134,7 +144,6 @@ var outputLogFormatter = function(log){
return log;
};
/**
* Formats the input of a whisper post and converts all values to HEX
*
@ -142,15 +151,15 @@ var outputLogFormatter = function(log){
* @param {Object} transaction object
* @returns {Object}
*/
var inputPostFormatter = function(post){
var inputPostFormatter = function(post) {
post.payload = utils.toHex(post.payload);
post.ttl = utils.fromDecimal(post.ttl);
post.priority = utils.fromDecimal(post.priority);
if(!(post.topics instanceof Array))
if(!utils.isArray(post.topics)) {
post.topics = [post.topics];
}
// format the following options
post.topics = post.topics.map(function(topic){
@ -176,10 +185,8 @@ var outputPostFormatter = function(post){
post.payloadRaw = post.payload;
post.payload = utils.toAscii(post.payload);
if(post.payload.indexOf('{') === 0 || post.payload.indexOf('[') === 0) {
try {
post.payload = JSON.parse(post.payload);
} catch (e) { }
if (utils.isJson(post.payload)) {
post.payload = JSON.parse(post.payload);
}
// format the following options
@ -191,13 +198,14 @@ var outputPostFormatter = function(post){
};
module.exports = {
convertToBigNumber: convertToBigNumber,
inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,
inputBlockNumberFormatter: inputBlockNumberFormatter,
inputTransactionFormatter: inputTransactionFormatter,
inputPostFormatter: inputPostFormatter,
outputBigNumberFormatter: outputBigNumberFormatter,
outputTransactionFormatter: outputTransactionFormatter,
inputCallFormatter: inputCallFormatter,
outputBlockFormatter: outputBlockFormatter,
outputLogFormatter: outputLogFormatter,
inputPostFormatter: inputPostFormatter,
outputPostFormatter: outputPostFormatter
};

56
lib/web3/httpprovider.js

@ -22,47 +22,39 @@
* @date 2014
*/
if (process.env.NODE_ENV !== 'build') {
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
}
"use strict";
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
var HttpProvider = function (host) {
this.name = 'HTTP';
this.handlers = [];
this.host = host || 'http://localhost:8080';
};
HttpProvider.prototype.send = function (payload, callback) {
HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest();
// ASYNC
if(typeof callback === 'function') {
request.onreadystatechange = function() {
if(request.readyState === 4) {
var result = '';
try {
result = JSON.parse(request.responseText);
} catch(error) {
result = error;
}
callback(result, request.status);
}
};
request.open('POST', this.host, true);
request.send(JSON.stringify(payload));
// SYNC
} else {
request.open('POST', this.host, false);
request.send(JSON.stringify(payload));
request.open('POST', this.host, false);
request.send(JSON.stringify(payload));
// check request.status
if(request.status !== 200)
return;
return JSON.parse(request.responseText);
// check request.status
// TODO: throw an error here! it cannot silently fail!!!
//if (request.status !== 200) {
//return;
//}
return JSON.parse(request.responseText);
};
}
HttpProvider.prototype.sendAsync = function (payload, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
// TODO: handle the error properly here!!!
callback(null, JSON.parse(request.responseText));
}
};
request.open('POST', this.host, true);
request.send(JSON.stringify(payload));
};
module.exports = HttpProvider;

66
lib/web3/jsonrpc.js

@ -20,13 +20,33 @@
* @date 2015
*/
var messageId = 1;
var Jsonrpc = function () {
// singleton pattern
if (arguments.callee._singletonInstance) {
return arguments.callee._singletonInstance;
}
arguments.callee._singletonInstance = this;
/// Should be called to valid json create payload object
/// @param method of jsonrpc call, required
/// @param params, an array of method params, optional
/// @returns valid jsonrpc payload object
var toPayload = function (method, params) {
this.messageId = 1;
};
/**
* @return {Jsonrpc} singleton
*/
Jsonrpc.getInstance = function () {
var instance = new Jsonrpc();
return instance;
};
/**
* Should be called to valid json create payload object
*
* @method toPayload
* @param {Function} method of jsonrpc call, required
* @param {Array} params, an array of method params, optional
* @returns {Object} valid jsonrpc payload object
*/
Jsonrpc.prototype.toPayload = function (method, params) {
if (!method)
console.error('jsonrpc method should be specified!');
@ -34,13 +54,18 @@ var toPayload = function (method, params) {
jsonrpc: '2.0',
method: method,
params: params || [],
id: messageId++
id: this.messageId++
};
};
/// Should be called to check if jsonrpc response is valid
/// @returns true if response is valid, otherwise false
var isValidResponse = function (response) {
/**
* Should be called to check if jsonrpc response is valid
*
* @method isValidResponse
* @param {Object}
* @returns {Boolean} true if response is valid, otherwise false
*/
Jsonrpc.prototype.isValidResponse = function (response) {
return !!response &&
!response.error &&
response.jsonrpc === '2.0' &&
@ -48,18 +73,19 @@ var isValidResponse = function (response) {
response.result !== undefined; // only undefined is not valid json object
};
/// Should be called to create batch payload object
/// @param messages, an array of objects with method (required) and params (optional) fields
var toBatchPayload = function (messages) {
/**
* Should be called to create batch payload object
*
* @method toBatchPayload
* @param {Array} messages, an array of objects with method (required) and params (optional) fields
* @returns {Array} batch payload
*/
Jsonrpc.prototype.toBatchPayload = function (messages) {
var self = this;
return messages.map(function (message) {
return toPayload(message.method, message.params);
return self.toPayload(message.method, message.params);
});
};
module.exports = {
toPayload: toPayload,
isValidResponse: isValidResponse,
toBatchPayload: toBatchPayload
};
module.exports = Jsonrpc;

159
lib/web3/method.js

@ -0,0 +1,159 @@
/*
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 method.js
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var RequestManager = require('./requestmanager');
var utils = require('../utils/utils');
var errors = require('./errors');
var Method = function (options) {
this.name = options.name;
this.call = options.call;
this.params = options.params || 0;
this.inputFormatter = options.inputFormatter;
this.outputFormatter = options.outputFormatter;
};
/**
* Should be used to determine name of the jsonrpc method based on arguments
*
* @method getCall
* @param {Array} arguments
* @return {String} name of jsonrpc method
*/
Method.prototype.getCall = function (args) {
return utils.isFunction(this.call) ? this.call(args) : this.call;
};
/**
* Should be used to extract callback from array of arguments. Modifies input param
*
* @method extractCallback
* @param {Array} arguments
* @return {Function|Null} callback, if exists
*/
Method.prototype.extractCallback = function (args) {
if (utils.isFunction(args[args.length - 1])) {
return args.pop(); // modify the args array!
}
return null;
};
/**
* Should be called to check if the number of arguments is correct
*
* @method validateArgs
* @param {Array} arguments
* @throws {Error} if it is not
*/
Method.prototype.validateArgs = function (args) {
if (args.length !== this.params) {
throw errors.InvalidNumberOfParams;
}
};
/**
* Should be called to format input args of method
*
* @method formatInput
* @param {Array}
* @return {Array}
*/
Method.prototype.formatInput = function (args) {
if (!this.inputFormatter) {
return args;
}
return this.inputFormatter.map(function (formatter, index) {
return formatter ? formatter(args[index]) : args[index];
});
};
/**
* Should be called to format output(result) of method
*
* @method formatOutput
* @param {Object}
* @return {Object}
*/
Method.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
};
/**
* Should attach function to method
*
* @method attachToObject
* @param {Object}
* @param {Function}
*/
Method.prototype.attachToObject = function (obj) {
var func = this.send.bind(this);
func.call = this.call; // that's ugly. filter.js uses it
var name = this.name.split('.');
if (name.length > 1) {
obj[name[0]] = obj[name[0]] || {};
obj[name[0]][name[1]] = func;
} else {
obj[name[0]] = func;
}
};
/**
* Should create payload from given input args
*
* @method toPayload
* @param {Array} args
* @return {Object}
*/
Method.prototype.toPayload = function (args) {
var call = this.getCall(args);
var callback = this.extractCallback(args);
var params = this.formatInput(args);
this.validateArgs(params);
return {
method: call,
params: params,
callback: callback
};
};
/**
* Should send request to the API
*
* @method send
* @param list of params
* @return result
*/
Method.prototype.send = function () {
var payload = this.toPayload(Array.prototype.slice.call(arguments));
if (payload.callback) {
var self = this;
return RequestManager.getInstance().sendAsync(payload, function (err, result) {
payload.callback(null, self.formatOutput(result));
});
}
return this.formatOutput(RequestManager.getInstance().send(payload));
};
module.exports = Method;

13
lib/web3/net.js

@ -21,16 +21,23 @@
*/
var utils = require('../utils/utils');
var Property = require('./property');
/// @returns an array of objects describing web3.eth api methods
var methods = [
// { name: 'getBalance', call: 'eth_balanceAt', outputFormatter: formatters.convertToBigNumber},
];
/// @returns an array of objects describing web3.eth api properties
var properties = [
{ name: 'listening', getter: 'net_listening'},
{ name: 'peerCount', getter: 'net_peerCount', outputFormatter: utils.toDecimal },
new Property({
name: 'listening',
getter: 'net_listening'
}),
new Property({
name: 'peerCount',
getter: 'net_peerCount',
outputFormatter: utils.toDecimal
})
];

104
lib/web3/property.js

@ -0,0 +1,104 @@
/*
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 property.js
* @author Fabian Vogelsteller <fabian@frozeman.de>
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var RequestManager = require('./requestmanager');
var Property = function (options) {
this.name = options.name;
this.getter = options.getter;
this.setter = options.setter;
this.outputFormatter = options.outputFormatter;
this.inputFormatter = options.inputFormatter;
};
/**
* Should be called to format input args of method
*
* @method formatInput
* @param {Array}
* @return {Array}
*/
Property.prototype.formatInput = function (arg) {
return this.inputFormatter ? this.inputFormatter(arg) : arg;
};
/**
* Should be called to format output(result) of method
*
* @method formatOutput
* @param {Object}
* @return {Object}
*/
Property.prototype.formatOutput = function (result) {
return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;
};
/**
* Should attach function to method
*
* @method attachToObject
* @param {Object}
* @param {Function}
*/
Property.prototype.attachToObject = function (obj) {
var proto = {
get: this.get.bind(this),
set: this.set.bind(this)
};
var name = this.name.split('.');
if (name.length > 1) {
obj[name[0]] = obj[name[0]] || {};
Object.defineProperty(obj[name[0]], name[1], proto);
} else {
Object.defineProperty(obj, name[0], proto);
}
};
/**
* Should be used to get value of the property
*
* @method get
* @return {Object} value of the property
*/
Property.prototype.get = function () {
return this.formatOutput(RequestManager.getInstance().send({
method: this.getter
}));
};
/**
* Should be used to set value of the property
*
* @method set
* @param {Object} new value of the property
*/
Property.prototype.set = function (value) {
return RequestManager.getInstance().send({
method: this.setter,
params: [this.formatInput(value)]
});
};
module.exports = Property;

292
lib/web3/requestmanager.js

@ -14,148 +14,206 @@
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 requestmanager.js
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
* Fabian Vogelsteller <fabian@ethdev.com>
* Gav Wood <g@ethdev.com>
/**
* @file requestmanager.js
* @author Jeffrey Wilcke <jeff@ethdev.com>
* @author Marek Kotewicz <marek@ethdev.com>
* @author Marian Oancea <marian@ethdev.com>
* @author Fabian Vogelsteller <fabian@ethdev.com>
* @author Gav Wood <g@ethdev.com>
* @date 2014
*/
var jsonrpc = require('./jsonrpc');
var Jsonrpc = require('./jsonrpc');
var utils = require('../utils/utils');
var c = require('../utils/config');
var errors = require('./errors');
/**
* It's responsible for passing messages to providers
* It's also responsible for polling the ethereum node for incoming messages
* Default poll timeout is 1 second
* Singleton
*/
var requestManager = function() {
var polls = [];
var timeout = null;
var provider;
var send = function (data, callback) {
/*jshint maxcomplexity: 8 */
// FORMAT BASED ON ONE FORMATTER function
if(typeof data.inputFormatter === 'function') {
data.params = Array.prototype.map.call(data.params, function(item, index){
// format everything besides the defaultblock, which is already formated
return (!data.addDefaultblock || index+1 < data.addDefaultblock) ? data.inputFormatter(item) : item;
});
// FORMAT BASED ON the input FORMATTER ARRAY
} else if(data.inputFormatter instanceof Array) {
data.params = Array.prototype.map.call(data.inputFormatter, function(formatter, index){
// format everything besides the defaultblock, which is already formated
return (!data.addDefaultblock || index+1 < data.addDefaultblock) ? formatter(data.params[index]) : data.params[index];
});
}
var RequestManager = function (provider) {
// singleton pattern
if (arguments.callee._singletonInstance) {
return arguments.callee._singletonInstance;
}
arguments.callee._singletonInstance = this;
this.provider = provider;
this.polls = [];
this.timeout = null;
this.poll();
};
/**
* @return {RequestManager} singleton
*/
RequestManager.getInstance = function () {
var instance = new RequestManager();
return instance;
};
var payload = jsonrpc.toPayload(data.method, data.params);
/**
* Should be used to synchronously send request
*
* @method send
* @param {Object} data
* @return {Object}
*/
RequestManager.prototype.send = function (data) {
if (!this.provider) {
console.error(errors.InvalidProvider);
return null;
}
if (!provider) {
console.error('provider is not set');
return null;
}
var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);
var result = this.provider.send(payload);
// HTTP ASYNC (only when callback is given, and it a HttpProvidor)
if(typeof callback === 'function' && provider.name === 'HTTP'){
provider.send(payload, function(result, status){
if (!jsonrpc.isValidResponse(result)) {
if(typeof result === 'object' && result.error && result.error.message) {
console.error(result.error.message);
callback(result.error);
} else {
callback(new Error({
status: status,
error: result,
message: 'Bad Request'
}));
}
return null;
}
// format the output
callback(null, (typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result);
});
// SYNC
} else {
var result = provider.send(payload);
if (!jsonrpc.isValidResponse(result)) {
if(typeof result === 'object' && result.error && result.error.message)
console.error(result.error.message);
return null;
}
if (!Jsonrpc.getInstance().isValidResponse(result)) {
throw errors.InvalidResponse(result);
}
// format the output
return (typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result;
return result.result;
};
/**
* Should be used to asynchronously send request
*
* @method sendAsync
* @param {Object} data
* @param {Function} callback
*/
RequestManager.prototype.sendAsync = function (data, callback) {
if (!this.provider) {
return callback(errors.InvalidProvider);
}
var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);
this.provider.sendAsync(payload, function (err, result) {
if (err) {
return callback(err);
}
};
if (!Jsonrpc.getInstance().isValidResponse(result)) {
return callback(errors.InvalidResponse(result));
}
callback(null, result.result);
});
};
/**
* Should be used to set provider of request manager
*
* @method setProvider
* @param {Object}
*/
RequestManager.prototype.setProvider = function (p) {
this.provider = p;
};
var setProvider = function (p) {
provider = p;
};
/*jshint maxparams:4 */
/*jshint maxparams:4 */
var startPolling = function (data, pollId, callback, uninstall) {
polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});
};
/*jshint maxparams:3 */
/**
* Should be used to start polling
*
* @method startPolling
* @param {Object} data
* @param {Number} pollId
* @param {Function} callback
* @param {Function} uninstall
*
* @todo cleanup number of params
*/
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});
};
/*jshint maxparams:3 */
var stopPolling = function (pollId) {
for (var i = polls.length; i--;) {
var poll = polls[i];
if (poll.id === pollId) {
polls.splice(i, 1);
}
/**
* Should be used to stop polling for filter with given id
*
* @method stopPolling
* @param {Number} pollId
*/
RequestManager.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);
}
};
}
};
var reset = function () {
polls.forEach(function (poll) {
poll.uninstall(poll.id);
});
polls = [];
/**
* Should be called to reset polling mechanism of request manager
*
* @method reset
*/
RequestManager.prototype.reset = function () {
this.polls.forEach(function (poll) {
poll.uninstall(poll.id);
});
this.polls = [];
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
this.poll();
};
if (timeout) {
clearTimeout(timeout);
timeout = null;
/**
* Should be called to poll for changes on filter with given id
*
* @method poll
*/
RequestManager.prototype.poll = function () {
this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);
if (!this.polls.length) {
return;
}
if (!this.provider) {
console.error(errors.InvalidProvider);
return;
}
var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) {
return data.data;
}));
var self = this;
this.provider.sendAsync(payload, function (error, results) {
// TODO: console log?
if (error) {
return;
}
poll();
};
var poll = function () {
polls.forEach(function (data) {
// send async
send(data.data, function(error, result){
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result);
});
if (!utils.isArray(results)) {
throw errors.InvalidResponse(results);
}
results.map(function (result, index) {
result.callback = self.polls[index].callback;
return result;
}).filter(function (result) {
var valid = Jsonrpc.getInstance().isValidResponse(result);
if (!valid) {
result.callback(errors.InvalidResponse(result));
}
return valid;
}).filter(function (result) {
return utils.isArray(result.result) && result.result.length > 0;
}).forEach(function (result) {
result.callback(null, result.result);
});
timeout = setTimeout(poll, c.ETH_POLLING_TIMEOUT);
};
poll();
return {
send: send,
setProvider: setProvider,
startPolling: startPolling,
stopPolling: stopPolling,
reset: reset
};
});
};
module.exports = requestManager;
module.exports = RequestManager;

52
lib/web3/shh.js

@ -20,21 +20,47 @@
* @date 2015
*/
var Method = require('./method');
var formatters = require('./formatters');
/// @returns an array of objects describing web3.shh api methods
var methods = function () {
return [
{ name: 'post', call: 'shh_post', inputFormatter: formatters.inputPostFormatter },
{ name: 'newIdentity', call: 'shh_newIdentity' },
{ name: 'hasIdentity', call: 'shh_hasIdentity' },
{ name: 'newGroup', call: 'shh_newGroup' },
{ name: 'addToGroup', call: 'shh_addToGroup' },
// deprecated
{ name: 'haveIdentity', call: 'shh_haveIdentity', newMethod: 'shh.hasIdentity' },
];
};
var post = new Method({
name: 'post',
call: 'shh_post',
params: 1,
inputFormatter: formatters.inputPostFormatter
});
var newIdentity = new Method({
name: 'newIdentity',
call: 'shh_newIdentity',
params: 0
});
var hasIdentity = new Method({
name: 'hasIdentity',
call: 'shh_hasIdentity',
params: 1
});
var newGroup = new Method({
name: 'newGroup',
call: 'shh_newGroup',
params: 0
});
var addToGroup = new Method({
name: 'addToGroup',
call: 'shh_addToGroup',
params: 0
});
var methods = [
post,
newIdentity,
hasIdentity,
newGroup,
addToGroup
];
module.exports = {
methods: methods

66
lib/web3/watches.js

@ -20,25 +20,77 @@
* @date 2015
*/
var Method = require('./method');
/// @returns an array of objects describing web3.eth.filter api methods
var eth = function () {
var newFilter = function (args) {
var newFilterCall = function (args) {
return typeof args[0] === 'string' ? 'eth_newBlockFilter' : 'eth_newFilter';
};
var newFilter = new Method({
name: 'newFilter',
call: newFilterCall,
params: 1
});
var uninstallFilter = new Method({
name: 'uninstallFilter',
call: 'eth_uninstallFilter',
params: 1
});
var getLogs = new Method({
name: 'getLogs',
call: 'eth_getFilterLogs',
params: 1
});
var poll = new Method({
name: 'poll',
call: 'eth_getFilterChanges',
params: 1
});
return [
{ name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'eth_uninstallFilter' },
{ name: 'getLogs', call: 'eth_getFilterLogs' }
newFilter,
uninstallFilter,
getLogs,
poll
];
};
/// @returns an array of objects describing web3.shh.watch api methods
var shh = function () {
var newFilter = new Method({
name: 'newFilter',
call: 'shh_newFilter',
params: 1
});
var uninstallFilter = new Method({
name: 'uninstallFilter',
call: 'shh_uninstallFilter',
params: 1
});
var getLogs = new Method({
name: 'getLogs',
call: 'shh_getMessages',
params: 1
});
var poll = new Method({
name: 'poll',
call: 'shh_getFilterChanges',
params: 1
});
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getLogs', call: 'shh_getMessages' }
newFilter,
uninstallFilter,
getLogs,
poll
];
};

3
package-init.js

@ -1,7 +1,8 @@
/* jshint ignore:start */
if(typeof web3 === 'undefined') {
web3 = require('web3');
web3 = require('ethereum.js');
BigNumber = require('bignumber.js');
}
/* jshint ignore:end */

8
package.js

@ -1,7 +1,7 @@
/* jshint ignore:start */
Package.describe({
name: 'ethereum:js',
version: '0.1.3',
version: '0.2.5',
summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC',
git: 'https://github.com/ethereum/ethereum.js',
// By default, Meteor will default to using README.md for documentation.
@ -12,10 +12,10 @@ Package.describe({
Package.onUse(function(api) {
api.versionsFrom('1.0.3.2');
api.use('3stack:bignumber@2.0.0', 'client');
// api.use('3stack:bignumber@2.0.0', 'client');
api.export('BigNumber', 'client');
api.export('web3', 'client');
// api.export('BigNumber', 'client');
api.export(['web3', 'BigNumber'], 'client');
api.addFiles('dist/ethereum.js', 'client');
api.addFiles('package-init.js', 'client');

30
package.json

@ -1,18 +1,19 @@
{
"name": "ethereum.js",
"name": "web3",
"namespace": "ethereum",
"version": "0.1.3",
"description": "Ethereum JavaScript API, middleware to talk to a ethreum node over RPC",
"version": "0.2.5",
"description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC",
"main": "./index.js",
"directories": {
"lib": "./lib"
},
"dependencies": {
"bignumber.js": ">=2.0.0",
"envify": "^3.0.0",
"unreachable-branch-transform": "^0.1.0",
"xmlhttprequest": "*"
},
"browser": {
"xmlhttprequest": "./lib/utils/browser-xhr.js"
},
"devDependencies": {
"bower": ">=1.3.0",
"browserify": ">=6.0",
@ -35,6 +36,7 @@
"karma-mocha": "^0.1.10",
"karma-safari-launcher": "^0.1.1",
"mocha": ">=2.1.0",
"sandboxed-module": "^2.0.0",
"vinyl-source-stream": "^1.0.0"
},
"scripts": {
@ -53,19 +55,6 @@
"bugs": {
"url": "https://github.com/ethereum/ethereum.js/issues"
},
"browserify": {
"transform": [
[
"envify",
{
"NODE_ENV": "build"
}
],
[
"unreachable-branch-transform"
]
]
},
"keywords": [
"ethereum",
"javascript",
@ -92,6 +81,11 @@
"name": "Fabian Vogelsteller",
"email": "fabian@frozeman.de",
"homepage": "http://frozeman.de"
},
{
"name": "Gav Wood",
"email": "g@ethdev.com",
"homepage": "http://gavwood.com"
}
],
"license": "LGPL-3.0"

2
test/abi.inputParser.js

@ -19,7 +19,7 @@ var description = [{
]
}];
describe('abi', function() {
describe('lib/solidity/abi', function() {
describe('inputParser', function() {
it('should parse input uint', function() {

2
test/abi.outputParser.js

@ -19,7 +19,7 @@ var description = [{
]
}];
describe('abi', function() {
describe('lib/solidity/abi', function() {
describe('outputParser', function() {
it('should parse output fixed bytes type', function() {

229
test/contract.js

@ -0,0 +1,229 @@
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../index');
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var utils = require('../lib/utils/utils');
var desc = [{
"name": "balance(address)",
"type": "function",
"inputs": [{
"name": "who",
"type": "address"
}],
"constant": true,
"outputs": [{
"name": "value",
"type": "uint256"
}]
}, {
"name": "send(address,uint256)",
"type": "function",
"inputs": [{
"name": "to",
"type": "address"
}, {
"name": "value",
"type": "uint256"
}],
"outputs": []
}, {
"name":"Changed",
"type":"event",
"inputs": [
{"name":"from","type":"address","indexed":true},
{"name":"amount","type":"uint256","indexed":true},
{"name":"t1","type":"uint256","indexed":false},
{"name":"t2","type":"uint256","indexed":false}
],
}];
var address = '0x1234567890123456789012345678901234567890';
describe('web3.eth.contract', function () {
describe('event', function () {
it('should create event filter', function (done) {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset(); // reset different polls
var sha3 = '0x5131231231231231231231';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('Changed(address,uint256,uint256,uint256)'));
} else if (step === 1) {
step = 2;
provider.injectResult(3);
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_newFilter');
assert.deepEqual(payload.params[0], {
topics: [
sha3,
'0x1234567890123456789012345678901234567890'
],
address: '0x1234567890123456789012345678901234567890'
});
} else if (step === 2 && utils.isArray(payload)) {
provider.injectBatchResults([[{
address: address,
topics: [
sha3,
'0x0000000000000000000000001234567890123456789012345678901234567890',
'0x0000000000000000000000000000000000000000000000000000000000000001'
],
number: 2,
data: '0x0000000000000000000000000000000000000000000000000000000000000001' +
'0000000000000000000000000000000000000000000000000000000000000008'
}]]);
var r = payload.filter(function (p) {
return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === 3;
});
assert.equal(r.length > 0, true);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.Changed({from: address}).watch(function(err, result) {
assert.equal(result.args.from, address);
assert.equal(result.args.amount, 1);
assert.equal(result.args.t1, 1);
assert.equal(result.args.t2, 8);
done();
});
});
it('should call constant function', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('balance(address)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address
}, 'latest']);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.balance(address);
});
it('should sendTransaction to contract function', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) +
'0000000000000000000000001234567890123456789012345678901234567890' +
'0000000000000000000000000000000000000000000000000000000000000011' ,
to: address
}]);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.send(address, 17);
});
it('should make a call with optional params', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('balance(address)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address,
from: address,
gas: '0xc350'
}, 'latest']);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.call({from: address, gas: 50000}).balance(address);
});
it('should sendTransaction with optional params', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
var sha3 = '0x5131231231231231231231';
var address = '0x1234567890123456789012345678901234567890';
provider.injectResult(sha3);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'web3_sha3');
assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)'));
} else if (step === 1) {
assert.equal(payload.method, 'eth_sendTransaction');
assert.deepEqual(payload.params, [{
data: sha3.slice(0, 10) +
'0000000000000000000000001234567890123456789012345678901234567890' +
'0000000000000000000000000000000000000000000000000000000000000011' ,
to: address,
from: address,
gas: '0xc350',
gasPrice: '0xbb8',
value: '0x2710'
}]);
}
});
var Contract = web3.eth.contract(desc);
var contract = new Contract(address);
contract.sendTransaction({from: address, gas: 50000, gasPrice: 3000, value: 10000}).send(address, 17);
});
});
});

26
test/event.inputParser.js

@ -2,7 +2,7 @@ var assert = require('assert');
var event = require('../lib/web3/event.js');
var f = require('../lib/solidity/formatters.js');
describe('event', function () {
describe('lib/web3/event', function () {
describe('inputParser', function () {
it('should create basic filter input object', function () {
@ -33,8 +33,6 @@ describe('event', function () {
var options = {
fromBlock: 1,
toBlock: 2,
offset: 3,
limit: 4
};
var e = {
name: 'Event',
@ -51,8 +49,6 @@ describe('event', function () {
assert.equal(result.topics[0], signature);
assert.equal(result.fromBlock, options.fromBlock);
assert.equal(result.toBlock, options.toBlock);
assert.equal(result.offset, options.offset);
assert.equal(result.limit, options.limit);
});
@ -63,9 +59,7 @@ describe('event', function () {
var signature = '0x987654';
var options = {
fromBlock: 1,
toBlock: 2,
offset: 3,
limit: 4
toBlock: 2
};
var e = {
name: 'Event',
@ -80,11 +74,9 @@ describe('event', function () {
assert.equal(result.address, address);
assert.equal(result.topics.length, 2);
assert.equal(result.topics[0], signature);
assert.equal(result.topics[1], f.formatInputInt(4));
assert.equal(result.topics[1], '0x' + f.formatInputInt(4));
assert.equal(result.fromBlock, options.fromBlock);
assert.equal(result.toBlock, options.toBlock);
assert.equal(result.offset, options.offset);
assert.equal(result.limit, options.limit);
});
@ -94,10 +86,8 @@ describe('event', function () {
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
fromBlock: 1,
toBlock: 2,
};
var e = {
name: 'Event',
@ -114,10 +104,8 @@ describe('event', function () {
assert.equal(result.topics[0], signature);
assert.equal(result.topics[1][0], f.formatInputInt(4));
assert.equal(result.topics[1][1], f.formatInputInt(69));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
assert.equal(result.fromBlock, options.fromBlock);
assert.equal(result.toBlock, options.toBlock);
});
});

6
test/event.outputParser.js

@ -1,7 +1,7 @@
var assert = require('assert');
var event = require('../lib/web3/event.js');
describe('event', function () {
describe('lib/web3/event', function () {
describe('outputParser', function () {
it('should parse basic event output object', function () {
@ -10,7 +10,7 @@ describe('event', function () {
"address":"0x78dfc5983baecf65f73e3de3a96cee24e6b7981e",
"data":"0x000000000000000000000000000000000000000000000000000000000000004b",
"number":2,
"topic":[
"topics":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001"
]
@ -43,7 +43,7 @@ describe('event', function () {
"000000000000000000000000000000000000000000000000000000000000004c" +
"0000000000000000000000000000000000000000000000000000000000000001",
"number":3,
"topic":[
"topics":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000005"

24
test/filter.methods.js

@ -1,24 +0,0 @@
var assert = require('assert');
var filter = require('../lib/web3/filter');
var u = require('./test.utils.js');
var empty = function () {};
var implementation = {
newFilter: empty,
getLogs: empty,
uninstallFilter: empty,
startPolling: empty,
stopPolling: empty,
};
describe('web3', function () {
describe('eth', function () {
describe('filter', function () {
var f = filter({}, implementation);
u.methodExists(f, 'watch');
u.methodExists(f, 'stopWatching');
u.methodExists(f, 'get');
});
});
});

24
test/formatters.inputDefaultBlockFormatter.js

@ -0,0 +1,24 @@
var chai = require('chai');
var assert = chai.assert;
var formatters = require('../lib/web3/formatters');
var tests = [
{ value: 'latest', expected: 'latest' },
{ value: 'pending', expected: 'pending' },
{ value: 'earliest', expected: 'earliest' },
{ value: 1, expected: '0x1' },
{ value: '0x1', expected: '0x1' }
];
describe('lib/web3/formatters', function () {
describe('inputDefaultBlockNumberFormatter', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {
assert.strictEqual(formatters.inputDefaultBlockNumberFormatter(test.value), test.expected);
});
});
});
});

3
test/formatters.inputPostFormatter.js

@ -1,6 +1,6 @@
var chai = require('chai');
var formatters = require('../lib/web3/formatters.js');
var assert = chai.assert;
var formatters = require('../lib/web3/formatters.js');
describe('formatters', function () {
describe('inputPostFormatter', function () {
@ -26,3 +26,4 @@ describe('formatters', function () {
});
});
});

11
test/formatters.inputTransactionFormatter.js

@ -1,4 +1,5 @@
var assert = require('assert');
var chai = require('chai');
var assert = chai.assert;
var formatters = require('../lib/web3/formatters.js');
var BigNumber = require('bignumber.js');
@ -7,19 +8,19 @@ describe('formatters', function () {
it('should return the correct value', function () {
assert.deepEqual(formatters.inputTransactionFormatter({
data: '0x34234kjh23kj4234',
data: '0x34234bf23bf4234',
value: new BigNumber(100),
from: '0x00000',
to: '0x00000',
gas: 1000,
gasPrice: new BigNumber(1000),
gasPrice: new BigNumber(1000)
}), {
data: '0x34234kjh23kj4234',
data: '0x34234bf23bf4234',
value: '0x64',
from: '0x00000',
to: '0x00000',
gas: '0x3e8',
gasPrice: '0x3e8',
gasPrice: '0x3e8'
});
});
});

8
test/formatters.outputTransactionFormatter.js

@ -12,7 +12,10 @@ describe('formatters', function () {
to: '0x00000',
value: '0x3e8',
gas: '0x3e8',
gasPrice: '0x3e8'
gasPrice: '0x3e8',
transactionIndex: '0x1',
blockNumber: '0x3e8',
blockHash: '0x34234bf23bf4234'
}), {
input: '0x34234kjh23kj4234',
from: '0x00000',
@ -20,6 +23,9 @@ describe('formatters', function () {
value: new BigNumber(1000),
gas: 1000,
gasPrice: new BigNumber(1000),
blockNumber: 1000,
blockHash: '0x34234bf23bf4234',
transactionIndex: 1
});
});
});

68
test/helpers/FakeHttpProvider.js

@ -0,0 +1,68 @@
var chai = require('chai');
var assert = require('assert');
var utils = require('../../lib/utils/utils');
var getResponseStub = function () {
return {
jsonrpc: '2.0',
id: 1,
result: 0
};
};
var FakeHttpProvider = function () {
this.response = getResponseStub();
this.error = null;
this.validation = null;
};
FakeHttpProvider.prototype.send = function (payload) {
assert.equal(utils.isArray(payload) || utils.isObject(payload), true);
// TODO: validate jsonrpc request
if (this.error) {
throw this.error;
}
if (this.validation) {
// imitate plain json object
this.validation(JSON.parse(JSON.stringify(payload)));
}
return this.response;
};
FakeHttpProvider.prototype.sendAsync = function (payload, callback) {
assert.equal(utils.isArray(payload) || utils.isObject(payload), true);
assert.equal(utils.isFunction(callback), true);
if (this.validation) {
// imitate plain json object
this.validation(JSON.parse(JSON.stringify(payload)), callback);
}
callback(this.error, this.response);
};
FakeHttpProvider.prototype.injectResponse = function (response) {
this.response = response;
};
FakeHttpProvider.prototype.injectResult = function (result) {
this.response = getResponseStub();
this.response.result = result;
};
FakeHttpProvider.prototype.injectBatchResults = function (results) {
this.response = results.map(function (r) {
var response = getResponseStub();
response.result = r;
return response;
});
};
FakeHttpProvider.prototype.injectError = function (error) {
this.error = error;
};
FakeHttpProvider.prototype.injectValidation = function (callback) {
this.validation = callback;
};
module.exports = FakeHttpProvider;

11
test/helpers/FakeQtNavigator.js

@ -0,0 +1,11 @@
var navigator = {
qt: {
callMethod: function (payload) {
return "{}";
}
}
};
module.exports = navigator;

31
test/helpers/FakeXMLHttpRequest.js

@ -0,0 +1,31 @@
var chai = require('chai');
var assert = chai.assert;
var FakeXMLHttpRequest = function () {
this.responseText = "{}";
this.readyState = 4;
this.onreadystatechange = null;
this.async = false;
};
FakeXMLHttpRequest.prototype.open = function (method, host, async) {
assert.equal(method, 'POST');
assert.notEqual(host, null);
assert.equal(async === false || async === true, true);
this.async = async;
};
FakeXMLHttpRequest.prototype.send = function (payload) {
assert.equal(typeof payload, 'string');
if (this.async) {
assert.equal(typeof this.onreadystatechange, 'function');
this.onreadystatechange();
return;
}
return this.responseText;
};
module.exports = {
XMLHttpRequest: FakeXMLHttpRequest
};

68
test/helpers/test.method.js

@ -0,0 +1,68 @@
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../../index');
var FakeHttpProvider = require('./FakeHttpProvider');
var runTests = function (obj, method, tests) {
var testName = obj ? 'web3.' + obj : 'web';
describe(testName, function () {
describe(method, function () {
tests.forEach(function (test, index) {
it('sync test: ' + index, function () {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult(test.result);
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call);
assert.deepEqual(payload.params, test.formattedArgs);
});
// when
var result = (obj)
? web3[obj][method].apply(null, test.args.slice(0))
: web3[method].apply(null, test.args.slice(0));
// then
assert.deepEqual(test.formattedResult, result);
});
it('async test: ' + index, function (done) {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult(test.result);
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call);
assert.deepEqual(payload.params, test.formattedArgs);
});
var args = test.args.slice(0);
// add callback
args.push(function (err, result) {
assert.deepEqual(test.formattedResult, result);
done();
});
// when
if(obj)
web3[obj][method].apply(null, args);
else
web3[method].apply(null, args);
});
});
});
});
};
module.exports = {
runTests: runTests
}

9
test/test.utils.js → test/helpers/test.utils.js

@ -1,13 +1,20 @@
var assert = require('assert');
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../../index');
var FakeHttpProvider = require('./FakeHttpProvider');
var methodExists = function (object, method) {
it('should have method ' + method + ' implemented', function() {
web3.setProvider(null);
assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented');
});
};
var propertyExists = function (object, property) {
it('should have property ' + property + ' implemented', function() {
// set dummy providor, to prevent error
web3.setProvider(new FakeHttpProvider());
assert.notEqual('undefined', typeof object[property], 'property ' + property + ' is not implemented');
});
};

33
test/httpprovider.js

@ -0,0 +1,33 @@
var chai = require('chai');
var assert = chai.assert;
var SandboxedModule = require('sandboxed-module');
SandboxedModule.registerBuiltInSourceTransformer('istanbul');
var HttpProvider = SandboxedModule.require('../lib/web3/httpprovider', {
requires: {
'xmlhttprequest': require('./helpers/FakeXMLHttpRequest')
}
});
describe('lib/web3/httpprovider', function () {
describe('send', function () {
it('should send basic request', function () {
var provider = new HttpProvider();
var result = provider.send({});
assert.equal(typeof result, 'object');
});
});
describe('sendAsync', function () {
it('should send basic async request', function (done) {
var provider = new HttpProvider();
provider.sendAsync({}, function (err, result) {
assert.equal(typeof result, 'object');
done();
});
});
});
});

23
test/jsonrpc.id.js

@ -0,0 +1,23 @@
var chai = require('chai');
var assert = chai.assert;
var Jsonrpc = require('../lib/web3/jsonrpc');
describe('lib/web3/jsonrpc', function () {
describe('id', function () {
it('should increment the id', function () {
// given
var a = Jsonrpc.getInstance();
var b = Jsonrpc.getInstance();
var method = 'm';
// when
var p1 = a.toPayload(method);
var p2 = b.toPayload(method);
// then
assert.equal(p2.id, p1.id + 1);
});
});
});

1
test/jsonrpc.isValidResponse.js

@ -1,5 +1,6 @@
var assert = require('assert');
var jsonrpc = require('../lib/web3/jsonrpc');
jsonrpc = new jsonrpc();
describe('jsonrpc', function () {
describe('isValidResponse', function () {

1
test/jsonrpc.toBatchPayload.js

@ -1,5 +1,6 @@
var assert = require('assert');
var jsonrpc = require('../lib/web3/jsonrpc');
jsonrpc = new jsonrpc();
describe('jsonrpc', function () {
describe('toBatchPayload', function () {

4
test/jsonrpc.toPayload.js

@ -1,5 +1,7 @@
var assert = require('assert');
var chai = require('chai');
var assert = chai.assert;
var jsonrpc = require('../lib/web3/jsonrpc');
jsonrpc = new jsonrpc();
describe('jsonrpc', function () {
describe('toPayload', function () {

44
test/method.attachToObject.js

@ -0,0 +1,44 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
var utils = require('../lib/utils/utils');
describe('lib/web3/method', function () {
describe('attachToObject', function () {
//it('attach simple function to an object', function () {
//// given
//var method = new Method({
//name: 'hello'
//});
//var object = {};
//var func = function () { return 1; };
//// when
//method.attachToObject(object, func);
//// then
//assert.equal(utils.isFunction(object.hello), true);
//assert.equal(object.hello(), 1);
//});
//it('attach nested function to an object', function () {
//// given
//var method = new Method({
//name: 'hello.world'
//});
//var object = {};
//var func = function () { return 1; };
//// when
//method.attachToObject(object, func);
//// then
//assert.equal(utils.isObject(object.hello), true);
//assert.equal(utils.isFunction(object.hello.world), true);
//assert.equal(object.hello.world(), 1);
//});
});
});

52
test/method.extractCallback.js

@ -0,0 +1,52 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
describe('lib/web3/method', function () {
describe('extractCallback', function () {
it('should extract callback', function () {
// given
var method = new Method({});
var callback = function () { };
var args = [1, callback]
// when
var result = method.extractCallback(args);
// then
assert.equal(args.length, 1);
assert.equal(callback, result);
});
it('should extract callback created using newFunction', function () {
// given
var method = new Method({});
var callback = new Function ();
var args = [1, callback]
// when
var result = method.extractCallback(args);
// then
assert.equal(args.length, 1);
assert.equal(callback, result);
});
it('should not extract the callback', function () {
// given
var method = new Method({});
var args = [1, 2]
// when
var result = method.extractCallback(args);
// then
assert.equal(args.length, 2);
assert.equal(result, null);
});
});
});

41
test/method.formatInput.js

@ -0,0 +1,41 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
describe('lib/web3/method', function () {
describe('formatInput', function () {
it('should format plain input', function () {
// given
var star = function (arg) {
return arg + '*';
};
var method = new Method({
inputFormatter: [star, star, star]
});
var args = ['1','2','3'];
var expectedArgs = ['1*', '2*', '3*'];
// when
var result = method.formatInput(args);
// then
assert.deepEqual(result, expectedArgs);
});
it('should do nothing if there is no formatter', function () {
// given
var method = new Method({});
var args = [1,2,3];
// when
var result = method.formatInput(args);
// then
assert.deepEqual(result, args);
});
});
});

43
test/method.formatOutput.js

@ -0,0 +1,43 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
describe('lib/web3/method', function () {
describe('formatOutput', function () {
it('should format plain output', function () {
// given
var formatter = function (args) {
return args.map(function (arg) {
return arg + '*';
});
};
var method = new Method({
outputFormatter: formatter
});
var args = ['1','2','3'];
var expectedArgs = ['1*', '2*', '3*'];
// when
var result = method.formatOutput(args);
// then
assert.deepEqual(result, expectedArgs);
});
it('should do nothing if there is no formatter', function () {
// given
var method = new Method({});
var args = [1,2,3];
// when
var result = method.formatOutput(args);
// then
assert.deepEqual(result, args);
});
});
});

46
test/method.getCall.js

@ -0,0 +1,46 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
describe('lib/web3/method', function () {
describe('getCall', function () {
it('should return call name', function () {
// given
var call = 'hello_call_world';
var method = new Method({
call: call
});
// when
var result = method.getCall();
// then
assert.equal(call, result);
});
it('should return call based on args', function () {
// given
var call = function (args) {
return args ? args.length.toString() : '0';
};
var method = new Method({
call: call
});
// when
var r0 = method.getCall();
var r1 = method.getCall([1]);
var r2 = method.getCall([1, 2]);
// then
assert.equal(r0, '0');
assert.equal(r1, '1');
assert.equal(r2, '2');
});
});
});

47
test/method.validateArgs.js

@ -0,0 +1,47 @@
var chai = require('chai');
var assert = chai.assert;
var Method = require('../lib/web3/method');
var errors = require('../lib/web3/errors');
describe('lib/web3/method', function () {
describe('validateArgs', function () {
it('should pass', function () {
// given
var method = new Method({
params: 1
});
var args = [1];
var args2 = ['heloas'];
// when
var test = function () { method.validateArgs(args); };
var test2 = function () { method.validateArgs(args2); };
// then
assert.doesNotThrow(test);
assert.doesNotThrow(test2);
});
it('should return call based on args', function () {
// given
var method = new Method({
params: 2
});
var args = [1];
var args2 = ['heloas', '12', 3];
// when
var test = function () { method.validateArgs(args); };
var test2 = function () { method.validateArgs(args2); };
// then
assert.throws(test, errors.InvalidNumberOfParams);
assert.throws(test2, errors.InvalidNumberOfParams);
});
});
});

1
test/mocha.opts

@ -1,2 +1 @@
--reporter spec

10
test/net.methods.js

@ -1,10 +0,0 @@
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./test.utils.js');
describe('web3', function() {
describe('net', function() {
u.propertyExists(web3.net, 'listening');
u.propertyExists(web3.net, 'peerCount');
});
});

5
test/node/app.js

@ -0,0 +1,5 @@
var web3 = require('ethereum.js');
console.log(web3.version.api);

14
test/node/package.json

@ -0,0 +1,14 @@
{
"name": "node",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"ethereum.js": "ethereum/ethereum.js#master"
}
}

69
test/polling.js

@ -0,0 +1,69 @@
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../index');
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var utils = require('../lib/utils/utils');
var tests = [{
protocol: 'eth',
args: ['pending'],
firstResult: 1,
firstPayload: {
method: "eth_newBlockFilter",
params: [
"pending"
]
},
secondResult: [null],
secondPayload: {
method: "eth_getFilterChanges"
}
}];
var testPolling = function (tests) {
describe('web3.eth.filter.polling', function () {
tests.forEach(function (test, index) {
it('should create && successfully poll filter', function (done) {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
provider.injectResult(test.firstResult);
var step = 0;
provider.injectValidation(function (payload) {
if (step === 0) {
step = 1;
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.firstPayload.method);
assert.deepEqual(payload.params, test.firstPayload.params);
} else if (step === 1 && utils.isArray(payload)) {
var r = payload.filter(function (p) {
return p.jsonrpc === '2.0' && p.method === test.secondPayload.method && p.params[0] === test.firstResult;
});
assert.equal(r.length > 0, true);
}
});
// when
var filter = web3[test.protocol].filter.apply(null, test.args);
provider.injectBatchResults([test.secondResult]);
filter.watch(function (err, result) {
if (test.err) {
// todo
} else {
assert.equal(result, test.secondResult[0]);
}
done();
});
});
});
});
};
testPolling(tests);

22
test/qtsyncprovider.js

@ -0,0 +1,22 @@
var chai = require('chai');
var assert = chai.assert;
var SandboxedModule = require('sandboxed-module');
SandboxedModule.registerBuiltInSourceTransformer('istanbul');
var QtSyncProvider = SandboxedModule.require('../lib/web3/qtsync', {
globals: {
navigator: require('./helpers/FakeQtNavigator')
}
});
describe('/lib/web3/qtsyncprovider', function () {
describe('send', function () {
it('should send basic request', function () {
var provider = new QtSyncProvider();
var result = provider.send({});
assert.equal(typeof result, 'object');
});
});
});

44
test/requestmanager.js

@ -0,0 +1,44 @@
var chai = require('chai');
var assert = chai.assert;
var RequestManager = require('../lib/web3/requestmanager');
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
// TODO: handling errors!
// TODO: validation of params!
describe('lib/web3/requestmanager', function () {
describe('send', function () {
it('should return expected result synchronously', function () {
var provider = new FakeHttpProvider();
var manager = RequestManager.getInstance();
manager.setProvider(provider);
var expected = 'hello_world';
provider.injectResult(expected);
var result = manager.send({
method: 'test',
params: [1,2,3]
});
assert.equal(expected, result);
});
it('should return expected result asynchronously', function (done) {
var provider = new FakeHttpProvider();
var manager = RequestManager.getInstance();
manager.setProvider(provider);
var expected = 'hello_world';
provider.injectResult(expected);
manager.sendAsync({
method: 'test',
params: [1,2,3]
}, function (error, result) {
assert.equal(error, null);
assert.equal(expected, result);
done();
});
});
});
});

45
test/shh.filter.js

@ -0,0 +1,45 @@
var chai = require('chai');
var web3 = require('../index');
var assert = chai.assert;
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var method = 'filter';
var tests = [{
args: [{
to: '0x47d33b27bb249a2dbab4c0612bf9caf4c1950855',
topics: ['0x324f5435', '0x564b4566f3453']
}],
formattedArgs: [{
to: '0x47d33b27bb249a2dbab4c0612bf9caf4c1950855',
topics: ['0x324f5435', '0x564b4566f3453']
}],
result: '0xf',
formattedResult: '0xf',
call: 'shh_newFilter'
}];
describe('shh', function () {
describe(method, function () {
tests.forEach(function (test, index) {
it('property test: ' + index, function () {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult(test.result);
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, test.call);
assert.deepEqual(payload.params, test.formattedArgs);
});
// call
web3.shh[method].apply(null, test.args);
});
});
});
});

16
test/shh.hasIdentity.js

@ -0,0 +1,16 @@
var chai = require('chai');
var web3 = require('../index');
var testMethod = require('./helpers/test.method.js');
var method = 'hasIdentity';
var tests = [{
args: ['0x2dbab4c0612bf9caf4c195085547dc0612bf9caf4c1950855'],
formattedArgs: ['0x2dbab4c0612bf9caf4c195085547dc0612bf9caf4c1950855'],
result: true,
formattedResult: true,
call: 'shh_'+ method
}];
testMethod.runTests('shh', method, tests);

48
test/signature.js

@ -0,0 +1,48 @@
var chai = require('chai');
var assert = chai.assert;
var utils = require('../lib/utils/utils');
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var signature = require('../lib/web3/signature');
var web3 = require('../index');
var tests = [{
method: 'functionSignatureFromAscii',
call: 'web3_sha3',
request: 'multiply',
formattedRequest: utils.fromAscii('multiply'),
result: '0x255d31552d29a21e93334e96055c6dca7cd329f5420ae74ec166d0c47f9f9843',
formattedResult: '0x255d3155'
},{
method: 'eventSignatureFromAscii',
call: 'web3_sha3',
request: 'multiply',
formattedRequest: utils.fromAscii('multiply'),
result: '0x255d31552d29a21e93334e96055c6dca7cd329f5420ae74ec166d0c47f9f9843',
formattedResult: '0x255d31552d29a21e93334e96055c6dca7cd329f5420ae74ec166d0c47f9f9843'
}];
describe('lib/web3/signature', function () {
tests.forEach(function (test, index) {
describe(test.method, function () {
it('should properly format and return signature of solidity functioni ' + index, function () {
// given
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult(test.result);
provider.injectValidation(function (payload) {
assert.equal(payload.method, test.call);
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.params[0], test.formattedRequest);
});
// when
var result = signature[test.method].call(null, test.request);
// then
assert.equal(result, test.formattedResult);
});
});
});
});

2
test/utils.extractDisplayName.js

@ -1,7 +1,7 @@
var assert = require('assert');
var utils = require('../lib/utils/utils.js');
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('extractDisplayName', function () {
it('should extract display name from method with no params', function () {

2
test/utils.extractTypeName.js

@ -1,7 +1,7 @@
var assert = require('assert');
var utils = require('../lib/utils/utils.js');
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('extractTypeName', function () {
it('should extract type name from method with no params', function () {

2
test/utils.filters.js

@ -1,7 +1,7 @@
var assert = require('assert');
var utils = require('../lib/utils/utils.js');
describe('utils', function() {
describe('lib/utils/utils', function() {
it('should filter functions and events from input array properly', function () {
// given

2
test/utils.fromDecimal.js

@ -31,7 +31,7 @@ var tests = [
{ value: '-0x0', expected: '0x0'}
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('fromDecimal', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {

2
test/utils.fromWei.js

@ -1,7 +1,7 @@
var assert = require('assert');
var utils = require('../lib/utils/utils.js');
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('fromWei', function () {
it('should return the correct value', function () {

4
test/utils.isAddress.js

@ -8,10 +8,10 @@ var tests = [
{ value: 'function', is: false},
{ value: {}, is: false},
{ value: '0xc6d9d2cd449a754c494264e1809c50e34d64562b', is: true },
{ value: 'c6d9d2cd449a754c494264e1809c50e34d64562b', is: true }
{ value: 'c6d9d2cd449a754c494264e1809c50e34d64562b', is: false }
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('isAddress', function () {
tests.forEach(function (test) {
it('shoud test if value ' + test.value + ' is address: ' + test.is, function () {

2
test/utils.isBigNumber.js

@ -15,7 +15,7 @@ var tests = [
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('isBigNumber', function () {
tests.forEach(function (test) {
it('shoud test if value ' + test.func + ' is BigNumber: ' + test.is, function () {

2
test/utils.isFunction.js

@ -9,7 +9,7 @@ var tests = [
{ func: {}, is: false}
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('isFunction', function () {
tests.forEach(function (test) {
it('shoud test if value ' + test.func + ' is function: ' + test.is, function () {

26
test/utils.isJson.js

@ -0,0 +1,26 @@
var chai = require('chai');
var utils = require('../lib/utils/utils.js');
var assert = chai.assert;
var tests = [
{ obj: function () {}, is: false},
{ obj: new Function(), is: false},
{ obj: 'function', is: false},
{ obj: {}, is: false},
{ obj: '[]', is: true},
{ obj: '[1, 2]', is: true},
{ obj: '{}', is: true},
{ obj: '{"a": 123, "b" :3,}', is: false},
{ obj: '{"c" : 2}', is: true}
];
describe('lib/utils/utils', function () {
describe('isJson', function () {
tests.forEach(function (test) {
it('shoud test if value ' + test.obj + ' is json: ' + test.is, function () {
assert.equal(utils.isJson(test.obj), test.is);
});
});
});
});

2
test/utils.isString.js

@ -10,7 +10,7 @@ var tests = [
{ value: new String('hello'), is: true}
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('isString', function () {
tests.forEach(function (test) {
it('shoud test if value ' + test.func + ' is string: ' + test.is, function () {

2
test/utils.toBigNumber.js

@ -34,7 +34,7 @@ var tests = [
{ value: new BigNumber(0), expected: '0'}
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('toBigNumber', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {

2
test/utils.toDecimal.js

@ -1,7 +1,7 @@
var assert = require('assert');
var utils = require('../lib/utils/utils.js');
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('toDecimal', function () {
it('should return the correct value', function () {

8
test/utils.toHex.js

@ -27,14 +27,16 @@ var tests = [
{ value: {test: 'test'}, expected: '0x7b2274657374223a2274657374227d'},
{ value: '{"test": "test"}', expected: '0x7b2274657374223a202274657374227d'},
{ value: 'myString', expected: '0x6d79537472696e67'},
{ value: new BigNumber(15), expected: '0xf'}
{ value: new BigNumber(15), expected: '0xf'},
{ value: true, expected: '0x1'},
{ value: false, expected: '0x0'}
];
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('toHex', function () {
tests.forEach(function (test) {
it('should turn ' + test.value + ' to ' + test.expected, function () {
assert.equal(utils.toHex(test.value), test.expected);
assert.strictEqual(utils.toHex(test.value), test.expected);
});
});
});

2
test/utils.toWei.js

@ -2,7 +2,7 @@ var chai = require('chai');
var utils = require('../lib/utils/utils');
var assert = chai.assert;
describe('utils', function () {
describe('lib/utils/utils', function () {
describe('toWei', function () {
it('should return the correct value', function () {

14
test/web3.db.getHex.js

@ -0,0 +1,14 @@
var testMethod = require('./helpers/test.method.js');
var method = 'getHex';
var tests = [{
args: ['myDB', 'myKey'],
formattedArgs: ['myDB', 'myKey'],
result: '0xf',
formattedResult: '0xf',
call: 'db_'+ method
}];
testMethod.runTests('db', method, tests);

16
test/web3.db.getString.js

@ -0,0 +1,16 @@
var chai = require('chai');
var web3 = require('../index');
var testMethod = require('./helpers/test.method.js');
var method = 'getString';
var tests = [{
args: ['myDB', 'myKey'],
formattedArgs: ['myDB', 'myKey'],
result: 'myValue',
formattedResult: 'myValue',
call: 'db_'+ method
}];
testMethod.runTests('db', method, tests);

10
test/db.methods.js → test/web3.db.methods.js

@ -1,10 +1,10 @@
var assert = require('assert');
var chai = require('chai');
var assert = chai.assert;
var web3 = require('../index.js');
var u = require('./test.utils.js');
var u = require('./helpers/test.utils.js');
describe('web3', function() {
describe('db', function() {
describe('web3.db', function() {
describe('methods', function() {
u.methodExists(web3.db, 'putHex');
u.methodExists(web3.db, 'getHex');
u.methodExists(web3.db, 'putString');

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save