merged develop

This commit is contained in:
Fabian Vogelsteller 2015-06-09 12:56:05 +02:00
commit bd6d9ba5b2
24 changed files with 1131 additions and 451 deletions

303
dist/web3-light.js vendored
View File

@ -800,11 +800,19 @@ var BigNumber = require('bignumber.js');
var ETH_UNITS = [ var ETH_UNITS = [
'wei', 'wei',
'Kwei', 'kwei',
'Mwei', 'Mwei',
'Gwei', 'Gwei',
'szabo', 'szabo',
'finney', 'finney',
'femtoether',
'picoether',
'nanoether',
'microether',
'milliether',
'nano',
'micro',
'milli',
'ether', 'ether',
'grand', 'grand',
'Mether', 'Mether',
@ -825,7 +833,7 @@ module.exports = {
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS, ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000, ETH_POLLING_TIMEOUT: 1000/2,
defaultBlock: 'latest', defaultBlock: 'latest',
defaultAccount: undefined defaultAccount: undefined
}; };
@ -911,22 +919,30 @@ module.exports = function (str, isNew) {
var BigNumber = require('bignumber.js'); var BigNumber = require('bignumber.js');
var unitMap = { var unitMap = {
'wei': '1', 'wei': '1',
'kwei': '1000', 'kwei': '1000',
'ada': '1000', 'ada': '1000',
'mwei': '1000000', 'femtoether': '1000',
'babbage': '1000000', 'mwei': '1000000',
'gwei': '1000000000', 'babbage': '1000000',
'shannon': '1000000000', 'picoether': '1000000',
'szabo': '1000000000000', 'gwei': '1000000000',
'finney': '1000000000000000', 'shannon': '1000000000',
'ether': '1000000000000000000', 'nanoether': '1000000000',
'kether': '1000000000000000000000', 'nano': '1000000000',
'grand': '1000000000000000000000', 'szabo': '1000000000000',
'einstein': '1000000000000000000000', 'microether': '1000000000000',
'mether': '1000000000000000000000000', 'micro': '1000000000000',
'gether': '1000000000000000000000000000', 'finney': '1000000000000000',
'tether': '1000000000000000000000000000000' 'milliether': '1000000000000000',
'milli': '1000000000000000',
'ether': '1000000000000000000',
'kether': '1000000000000000000000',
'grand': '1000000000000000000000',
'einstein': '1000000000000000000000',
'mether': '1000000000000000000000000',
'gether': '1000000000000000000000000000',
'tether': '1000000000000000000000000000000'
}; };
/** /**
@ -1125,13 +1141,14 @@ var getValueOfUnit = function (unit) {
* Takes a number of wei and converts it to any other ether unit. * Takes a number of wei and converts it to any other ether unit.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether
@ -1151,13 +1168,14 @@ var fromWei = function(number, unit) {
* Takes a number of a unit and converts it to wei. * Takes a number of a unit and converts it to wei.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether
@ -1475,8 +1493,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) {
return fil(eventParams, options); return fil(eventParams, options);
} }
// what outputLogFormatter? that's wrong // output logs works for blockFilter and pendingTransaction filters?
//return new Filter(fil, watches.eth(), formatters.outputLogFormatter);
return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -1531,6 +1548,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', {
} }
}); });
// EXTEND
web3._extend = function(extension){
/*jshint maxcomplexity: 6 */
if(extension.property && !web3[extension.property])
web3[extension.property] = {};
setupMethods(web3[extension.property] || web3, extension.methods || []);
setupProperties(web3[extension.property] || web3, extension.properties || []);
};
web3._extend.formatters = formatters;
web3._extend.utils = utils;
web3._extend.Method = require('./web3/method');
web3._extend.Property = require('./web3/property');
/// setups all api methods /// setups all api methods
setupProperties(web3, web3Properties); setupProperties(web3, web3Properties);
setupMethods(web3.net, net.methods); setupMethods(web3.net, net.methods);
@ -1543,7 +1577,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3; module.exports = web3;
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){ },{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/method":22,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -2437,21 +2471,36 @@ var getOptions = function (options) {
}; };
}; };
var Filter = function (options, methods, formatter) { /**
var implementation = {}; Adds the callback and sets up the methods, to iterate over the results.
methods.forEach(function (method) {
method.attachToObject(implementation); @method getLogsAtStart
}); @param {Object} self
this.options = getOptions(options); @param {funciton}
this.implementation = implementation; */
this.callbacks = []; var getLogsAtStart = function(self, callback){
this.formatter = formatter; // call getFilterLogs for the first watch callback start
this.filterId = this.implementation.newFilter(this.options); if (!utils.isString(self.options)) {
self.get(function (err, messages) {
// don't send all the responses to all the watches again... just to self one
if (err) {
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
});
}
}; };
Filter.prototype.watch = function (callback) { /**
this.callbacks.push(callback); Adds the callback and sets up the methods, to iterate over the results.
var self = this;
@method pollFilter
@param {Object} self
*/
var pollFilter = function(self) {
var onMessage = function (error, messages) { var onMessage = function (error, messages) {
if (error) { if (error) {
@ -2468,29 +2517,55 @@ Filter.prototype.watch = function (callback) {
}); });
}; };
// call getFilterLogs on start RequestManager.getInstance().startPolling({
if (!utils.isString(this.options)) { method: self.implementation.poll.call,
this.get(function (err, messages) { params: [self.filterId],
// don't send all the responses to all the watches again... just to this one }, self.filterId, onMessage, self.stopWatching.bind(self));
if (err) {
callback(err);
}
messages.forEach(function (message) { };
callback(null, message);
var Filter = function (options, methods, formatter) {
var self = this;
var implementation = {};
methods.forEach(function (method) {
method.attachToObject(implementation);
});
this.options = getOptions(options);
this.implementation = implementation;
this.callbacks = [];
this.pollFilters = [];
this.formatter = formatter;
this.implementation.newFilter(this.options, function(error, id){
if(error) {
self.callbacks.forEach(function(callback){
callback(error);
}); });
}); } else {
self.filterId = id;
// get filter logs at start
self.callbacks.forEach(function(callback){
getLogsAtStart(self, callback);
});
pollFilter(self);
}
});
};
Filter.prototype.watch = function (callback) {
this.callbacks.push(callback);
if(this.filterId) {
getLogsAtStart(this, callback);
pollFilter(this);
} }
RequestManager.getInstance().startPolling({ return this;
method: this.implementation.poll.call,
params: [this.filterId],
}, this.filterId, onMessage, this.stopWatching.bind(this));
}; };
Filter.prototype.stopWatching = function () { Filter.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.filterId); RequestManager.getInstance().stopPolling(this.filterId);
this.implementation.uninstallFilter(this.filterId); // remove filter async
this.implementation.uninstallFilter(this.filterId, function(){});
this.callbacks = []; this.callbacks = [];
}; };
@ -2512,6 +2587,8 @@ Filter.prototype.get = function (callback) {
return self.formatter ? self.formatter(log) : log; return self.formatter ? self.formatter(log) : log;
}); });
} }
return this;
}; };
module.exports = Filter; module.exports = Filter;
@ -2609,8 +2686,10 @@ var inputTransactionFormatter = function (options){
* @returns {Object} transaction * @returns {Object} transaction
*/ */
var outputTransactionFormatter = function (tx){ var outputTransactionFormatter = function (tx){
tx.blockNumber = utils.toDecimal(tx.blockNumber); if(tx.blockNumber !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.blockNumber = utils.toDecimal(tx.blockNumber);
if(tx.transactionIndex !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.nonce = utils.toDecimal(tx.nonce); tx.nonce = utils.toDecimal(tx.nonce);
tx.gas = utils.toDecimal(tx.gas); tx.gas = utils.toDecimal(tx.gas);
tx.gasPrice = utils.toBigNumber(tx.gasPrice); tx.gasPrice = utils.toBigNumber(tx.gasPrice);
@ -2632,7 +2711,8 @@ var outputBlockFormatter = function(block) {
block.gasUsed = utils.toDecimal(block.gasUsed); block.gasUsed = utils.toDecimal(block.gasUsed);
block.size = utils.toDecimal(block.size); block.size = utils.toDecimal(block.size);
block.timestamp = utils.toDecimal(block.timestamp); block.timestamp = utils.toDecimal(block.timestamp);
block.number = utils.toDecimal(block.number); if(block.number !== null)
block.number = utils.toDecimal(block.number);
block.difficulty = utils.toBigNumber(block.difficulty); block.difficulty = utils.toBigNumber(block.difficulty);
block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
@ -2659,9 +2739,12 @@ var outputLogFormatter = function(log) {
return null; return null;
} }
log.blockNumber = utils.toDecimal(log.blockNumber); if(log.blockNumber !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex); log.blockNumber = utils.toDecimal(log.blockNumber);
log.logIndex = utils.toDecimal(log.logIndex); if(log.transactionIndex !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex);
if(log.logIndex !== null)
log.logIndex = utils.toDecimal(log.logIndex);
return log; return log;
}; };
@ -2763,6 +2846,7 @@ module.exports = {
var web3 = require('../web3'); var web3 = require('../web3');
var coder = require('../solidity/coder'); var coder = require('../solidity/coder');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var formatters = require('./formatters');
var sha3 = require('../utils/sha3'); var sha3 = require('../utils/sha3');
/** /**
@ -2786,6 +2870,12 @@ SolidityFunction.prototype.extractCallback = function (args) {
} }
}; };
SolidityFunction.prototype.extractDefaultBlock = function (args) {
if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {
return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array!
}
};
/** /**
* Should be used to create payload from arguments * Should be used to create payload from arguments
* *
@ -2837,15 +2927,17 @@ SolidityFunction.prototype.unpackOutput = function (output) {
SolidityFunction.prototype.call = function () { SolidityFunction.prototype.call = function () {
var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });
var callback = this.extractCallback(args); var callback = this.extractCallback(args);
var defaultBlock = this.extractDefaultBlock(args);
var payload = this.toPayload(args); var payload = this.toPayload(args);
if (!callback) { if (!callback) {
var output = web3.eth.call(payload); var output = web3.eth.call(payload, defaultBlock);
return this.unpackOutput(output); return this.unpackOutput(output);
} }
var self = this; var self = this;
web3.eth.call(payload, function (error, output) { web3.eth.call(payload, defaultBlock, function (error, output) {
callback(error, self.unpackOutput(output)); callback(error, self.unpackOutput(output));
}); });
}; };
@ -2964,7 +3056,7 @@ SolidityFunction.prototype.attachToContract = function (contract) {
module.exports = SolidityFunction; module.exports = SolidityFunction;
},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(require,module,exports){ },{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],19:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -3002,6 +3094,7 @@ HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -3045,6 +3138,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}; };
request.open('POST', this.host, true); request.open('POST', this.host, true);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -3730,9 +3824,9 @@ var RequestManager = function (provider) {
arguments.callee._singletonInstance = this; arguments.callee._singletonInstance = this;
this.provider = provider; this.provider = provider;
this.polls = []; this.polls = {};
this.timeout = null; this.timeout = null;
this.poll(); this.isPolling = false;
}; };
/** /**
@ -3827,6 +3921,11 @@ RequestManager.prototype.sendBatch = function (data, callback) {
*/ */
RequestManager.prototype.setProvider = function (p) { RequestManager.prototype.setProvider = function (p) {
this.provider = p; this.provider = p;
if(this.provider && !this.isPolling) {
this.poll();
this.isPolling = true;
}
}; };
/*jshint maxparams:4 */ /*jshint maxparams:4 */
@ -3843,7 +3942,7 @@ RequestManager.prototype.setProvider = function (p) {
* @todo cleanup number of params * @todo cleanup number of params
*/ */
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -3854,24 +3953,21 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst
* @param {Number} pollId * @param {Number} pollId
*/ */
RequestManager.prototype.stopPolling = function (pollId) { RequestManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) { delete this.polls['poll_'+ pollId];
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
}; };
/** /**
* Should be called to reset polling mechanism of request manager * Should be called to reset the polling mechanism of the request manager
* *
* @method reset * @method reset
*/ */
RequestManager.prototype.reset = function () { RequestManager.prototype.reset = function () {
this.polls.forEach(function (poll) { for (var key in this.polls) {
poll.uninstall(poll.id); if (this.polls.hasOwnProperty(key)) {
}); this.polls[key].uninstall();
this.polls = []; }
}
this.polls = {};
if (this.timeout) { if (this.timeout) {
clearTimeout(this.timeout); clearTimeout(this.timeout);
@ -3886,9 +3982,10 @@ RequestManager.prototype.reset = function () {
* @method poll * @method poll
*/ */
RequestManager.prototype.poll = function () { RequestManager.prototype.poll = function () {
/*jshint maxcomplexity: 6 */
this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);
if (!this.polls.length) { if (this.polls === {}) {
return; return;
} }
@ -3897,9 +3994,20 @@ RequestManager.prototype.poll = function () {
return; return;
} }
var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { var pollsData = [];
return data.data; var pollsKeys = [];
})); for (var key in this.polls) {
if (this.polls.hasOwnProperty(key)) {
pollsData.push(this.polls[key].data);
pollsKeys.push(key);
}
}
if (pollsData.length === 0) {
return;
}
var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);
var self = this; var self = this;
this.provider.sendAsync(payload, function (error, results) { this.provider.sendAsync(payload, function (error, results) {
@ -3913,8 +4021,15 @@ RequestManager.prototype.poll = function () {
} }
results.map(function (result, index) { results.map(function (result, index) {
result.callback = self.polls[index].callback; var key = pollsKeys[index];
return result; // make sure the filter is still installed after arrival of the request
if(self.polls[key]) {
result.callback = self.polls[key].callback;
return result;
} else
return false;
}).filter(function (result) {
return (!result) ? false : true;
}).filter(function (result) { }).filter(function (result) {
var valid = Jsonrpc.getInstance().isValidResponse(result); var valid = Jsonrpc.getInstance().isValidResponse(result);
if (!valid) { if (!valid) {
@ -4130,11 +4245,11 @@ var eth = function () {
switch(type) { switch(type) {
case 'latest': case 'latest':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newBlockFilter'; return 'eth_newBlockFilter';
case 'pending': case 'pending':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newPendingTransactionFilter'; return 'eth_newPendingTransactionFilter';
default: default:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

303
dist/web3.js vendored
View File

@ -800,11 +800,19 @@ var BigNumber = require('bignumber.js');
var ETH_UNITS = [ var ETH_UNITS = [
'wei', 'wei',
'Kwei', 'kwei',
'Mwei', 'Mwei',
'Gwei', 'Gwei',
'szabo', 'szabo',
'finney', 'finney',
'femtoether',
'picoether',
'nanoether',
'microether',
'milliether',
'nano',
'micro',
'milli',
'ether', 'ether',
'grand', 'grand',
'Mether', 'Mether',
@ -825,7 +833,7 @@ module.exports = {
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS, ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000, ETH_POLLING_TIMEOUT: 1000/2,
defaultBlock: 'latest', defaultBlock: 'latest',
defaultAccount: undefined defaultAccount: undefined
}; };
@ -911,22 +919,30 @@ module.exports = function (str, isNew) {
var BigNumber = require('bignumber.js'); var BigNumber = require('bignumber.js');
var unitMap = { var unitMap = {
'wei': '1', 'wei': '1',
'kwei': '1000', 'kwei': '1000',
'ada': '1000', 'ada': '1000',
'mwei': '1000000', 'femtoether': '1000',
'babbage': '1000000', 'mwei': '1000000',
'gwei': '1000000000', 'babbage': '1000000',
'shannon': '1000000000', 'picoether': '1000000',
'szabo': '1000000000000', 'gwei': '1000000000',
'finney': '1000000000000000', 'shannon': '1000000000',
'ether': '1000000000000000000', 'nanoether': '1000000000',
'kether': '1000000000000000000000', 'nano': '1000000000',
'grand': '1000000000000000000000', 'szabo': '1000000000000',
'einstein': '1000000000000000000000', 'microether': '1000000000000',
'mether': '1000000000000000000000000', 'micro': '1000000000000',
'gether': '1000000000000000000000000000', 'finney': '1000000000000000',
'tether': '1000000000000000000000000000000' 'milliether': '1000000000000000',
'milli': '1000000000000000',
'ether': '1000000000000000000',
'kether': '1000000000000000000000',
'grand': '1000000000000000000000',
'einstein': '1000000000000000000000',
'mether': '1000000000000000000000000',
'gether': '1000000000000000000000000000',
'tether': '1000000000000000000000000000000'
}; };
/** /**
@ -1125,13 +1141,14 @@ var getValueOfUnit = function (unit) {
* Takes a number of wei and converts it to any other ether unit. * Takes a number of wei and converts it to any other ether unit.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether
@ -1151,13 +1168,14 @@ var fromWei = function(number, unit) {
* Takes a number of a unit and converts it to wei. * Takes a number of a unit and converts it to wei.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether
@ -1475,8 +1493,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) {
return fil(eventParams, options); return fil(eventParams, options);
} }
// what outputLogFormatter? that's wrong // output logs works for blockFilter and pendingTransaction filters?
//return new Filter(fil, watches.eth(), formatters.outputLogFormatter);
return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -1531,6 +1548,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', {
} }
}); });
// EXTEND
web3._extend = function(extension){
/*jshint maxcomplexity: 6 */
if(extension.property && !web3[extension.property])
web3[extension.property] = {};
setupMethods(web3[extension.property] || web3, extension.methods || []);
setupProperties(web3[extension.property] || web3, extension.properties || []);
};
web3._extend.formatters = formatters;
web3._extend.utils = utils;
web3._extend.Method = require('./web3/method');
web3._extend.Property = require('./web3/property');
/// setups all api methods /// setups all api methods
setupProperties(web3, web3Properties); setupProperties(web3, web3Properties);
setupMethods(web3.net, net.methods); setupMethods(web3.net, net.methods);
@ -1543,7 +1577,7 @@ setupMethods(web3.shh, shh.methods);
module.exports = web3; module.exports = web3;
},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){ },{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/method":22,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -2437,21 +2471,36 @@ var getOptions = function (options) {
}; };
}; };
var Filter = function (options, methods, formatter) { /**
var implementation = {}; Adds the callback and sets up the methods, to iterate over the results.
methods.forEach(function (method) {
method.attachToObject(implementation); @method getLogsAtStart
}); @param {Object} self
this.options = getOptions(options); @param {funciton}
this.implementation = implementation; */
this.callbacks = []; var getLogsAtStart = function(self, callback){
this.formatter = formatter; // call getFilterLogs for the first watch callback start
this.filterId = this.implementation.newFilter(this.options); if (!utils.isString(self.options)) {
self.get(function (err, messages) {
// don't send all the responses to all the watches again... just to self one
if (err) {
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
});
}
}; };
Filter.prototype.watch = function (callback) { /**
this.callbacks.push(callback); Adds the callback and sets up the methods, to iterate over the results.
var self = this;
@method pollFilter
@param {Object} self
*/
var pollFilter = function(self) {
var onMessage = function (error, messages) { var onMessage = function (error, messages) {
if (error) { if (error) {
@ -2468,29 +2517,55 @@ Filter.prototype.watch = function (callback) {
}); });
}; };
// call getFilterLogs on start RequestManager.getInstance().startPolling({
if (!utils.isString(this.options)) { method: self.implementation.poll.call,
this.get(function (err, messages) { params: [self.filterId],
// don't send all the responses to all the watches again... just to this one }, self.filterId, onMessage, self.stopWatching.bind(self));
if (err) {
callback(err);
}
messages.forEach(function (message) { };
callback(null, message);
var Filter = function (options, methods, formatter) {
var self = this;
var implementation = {};
methods.forEach(function (method) {
method.attachToObject(implementation);
});
this.options = getOptions(options);
this.implementation = implementation;
this.callbacks = [];
this.pollFilters = [];
this.formatter = formatter;
this.implementation.newFilter(this.options, function(error, id){
if(error) {
self.callbacks.forEach(function(callback){
callback(error);
}); });
}); } else {
self.filterId = id;
// get filter logs at start
self.callbacks.forEach(function(callback){
getLogsAtStart(self, callback);
});
pollFilter(self);
}
});
};
Filter.prototype.watch = function (callback) {
this.callbacks.push(callback);
if(this.filterId) {
getLogsAtStart(this, callback);
pollFilter(this);
} }
RequestManager.getInstance().startPolling({ return this;
method: this.implementation.poll.call,
params: [this.filterId],
}, this.filterId, onMessage, this.stopWatching.bind(this));
}; };
Filter.prototype.stopWatching = function () { Filter.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.filterId); RequestManager.getInstance().stopPolling(this.filterId);
this.implementation.uninstallFilter(this.filterId); // remove filter async
this.implementation.uninstallFilter(this.filterId, function(){});
this.callbacks = []; this.callbacks = [];
}; };
@ -2512,6 +2587,8 @@ Filter.prototype.get = function (callback) {
return self.formatter ? self.formatter(log) : log; return self.formatter ? self.formatter(log) : log;
}); });
} }
return this;
}; };
module.exports = Filter; module.exports = Filter;
@ -2609,8 +2686,10 @@ var inputTransactionFormatter = function (options){
* @returns {Object} transaction * @returns {Object} transaction
*/ */
var outputTransactionFormatter = function (tx){ var outputTransactionFormatter = function (tx){
tx.blockNumber = utils.toDecimal(tx.blockNumber); if(tx.blockNumber !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.blockNumber = utils.toDecimal(tx.blockNumber);
if(tx.transactionIndex !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.nonce = utils.toDecimal(tx.nonce); tx.nonce = utils.toDecimal(tx.nonce);
tx.gas = utils.toDecimal(tx.gas); tx.gas = utils.toDecimal(tx.gas);
tx.gasPrice = utils.toBigNumber(tx.gasPrice); tx.gasPrice = utils.toBigNumber(tx.gasPrice);
@ -2632,7 +2711,8 @@ var outputBlockFormatter = function(block) {
block.gasUsed = utils.toDecimal(block.gasUsed); block.gasUsed = utils.toDecimal(block.gasUsed);
block.size = utils.toDecimal(block.size); block.size = utils.toDecimal(block.size);
block.timestamp = utils.toDecimal(block.timestamp); block.timestamp = utils.toDecimal(block.timestamp);
block.number = utils.toDecimal(block.number); if(block.number !== null)
block.number = utils.toDecimal(block.number);
block.difficulty = utils.toBigNumber(block.difficulty); block.difficulty = utils.toBigNumber(block.difficulty);
block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
@ -2659,9 +2739,12 @@ var outputLogFormatter = function(log) {
return null; return null;
} }
log.blockNumber = utils.toDecimal(log.blockNumber); if(log.blockNumber !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex); log.blockNumber = utils.toDecimal(log.blockNumber);
log.logIndex = utils.toDecimal(log.logIndex); if(log.transactionIndex !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex);
if(log.logIndex !== null)
log.logIndex = utils.toDecimal(log.logIndex);
return log; return log;
}; };
@ -2763,6 +2846,7 @@ module.exports = {
var web3 = require('../web3'); var web3 = require('../web3');
var coder = require('../solidity/coder'); var coder = require('../solidity/coder');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var formatters = require('./formatters');
var sha3 = require('../utils/sha3'); var sha3 = require('../utils/sha3');
/** /**
@ -2786,6 +2870,12 @@ SolidityFunction.prototype.extractCallback = function (args) {
} }
}; };
SolidityFunction.prototype.extractDefaultBlock = function (args) {
if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {
return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array!
}
};
/** /**
* Should be used to create payload from arguments * Should be used to create payload from arguments
* *
@ -2837,15 +2927,17 @@ SolidityFunction.prototype.unpackOutput = function (output) {
SolidityFunction.prototype.call = function () { SolidityFunction.prototype.call = function () {
var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });
var callback = this.extractCallback(args); var callback = this.extractCallback(args);
var defaultBlock = this.extractDefaultBlock(args);
var payload = this.toPayload(args); var payload = this.toPayload(args);
if (!callback) { if (!callback) {
var output = web3.eth.call(payload); var output = web3.eth.call(payload, defaultBlock);
return this.unpackOutput(output); return this.unpackOutput(output);
} }
var self = this; var self = this;
web3.eth.call(payload, function (error, output) { web3.eth.call(payload, defaultBlock, function (error, output) {
callback(error, self.unpackOutput(output)); callback(error, self.unpackOutput(output));
}); });
}; };
@ -2964,7 +3056,7 @@ SolidityFunction.prototype.attachToContract = function (contract) {
module.exports = SolidityFunction; module.exports = SolidityFunction;
},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(require,module,exports){ },{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],19:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -3002,6 +3094,7 @@ HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -3045,6 +3138,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}; };
request.open('POST', this.host, true); request.open('POST', this.host, true);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -3730,9 +3824,9 @@ var RequestManager = function (provider) {
arguments.callee._singletonInstance = this; arguments.callee._singletonInstance = this;
this.provider = provider; this.provider = provider;
this.polls = []; this.polls = {};
this.timeout = null; this.timeout = null;
this.poll(); this.isPolling = false;
}; };
/** /**
@ -3827,6 +3921,11 @@ RequestManager.prototype.sendBatch = function (data, callback) {
*/ */
RequestManager.prototype.setProvider = function (p) { RequestManager.prototype.setProvider = function (p) {
this.provider = p; this.provider = p;
if(this.provider && !this.isPolling) {
this.poll();
this.isPolling = true;
}
}; };
/*jshint maxparams:4 */ /*jshint maxparams:4 */
@ -3843,7 +3942,7 @@ RequestManager.prototype.setProvider = function (p) {
* @todo cleanup number of params * @todo cleanup number of params
*/ */
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -3854,24 +3953,21 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst
* @param {Number} pollId * @param {Number} pollId
*/ */
RequestManager.prototype.stopPolling = function (pollId) { RequestManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) { delete this.polls['poll_'+ pollId];
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
}; };
/** /**
* Should be called to reset polling mechanism of request manager * Should be called to reset the polling mechanism of the request manager
* *
* @method reset * @method reset
*/ */
RequestManager.prototype.reset = function () { RequestManager.prototype.reset = function () {
this.polls.forEach(function (poll) { for (var key in this.polls) {
poll.uninstall(poll.id); if (this.polls.hasOwnProperty(key)) {
}); this.polls[key].uninstall();
this.polls = []; }
}
this.polls = {};
if (this.timeout) { if (this.timeout) {
clearTimeout(this.timeout); clearTimeout(this.timeout);
@ -3886,9 +3982,10 @@ RequestManager.prototype.reset = function () {
* @method poll * @method poll
*/ */
RequestManager.prototype.poll = function () { RequestManager.prototype.poll = function () {
/*jshint maxcomplexity: 6 */
this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);
if (!this.polls.length) { if (this.polls === {}) {
return; return;
} }
@ -3897,9 +3994,20 @@ RequestManager.prototype.poll = function () {
return; return;
} }
var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { var pollsData = [];
return data.data; var pollsKeys = [];
})); for (var key in this.polls) {
if (this.polls.hasOwnProperty(key)) {
pollsData.push(this.polls[key].data);
pollsKeys.push(key);
}
}
if (pollsData.length === 0) {
return;
}
var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);
var self = this; var self = this;
this.provider.sendAsync(payload, function (error, results) { this.provider.sendAsync(payload, function (error, results) {
@ -3913,8 +4021,15 @@ RequestManager.prototype.poll = function () {
} }
results.map(function (result, index) { results.map(function (result, index) {
result.callback = self.polls[index].callback; var key = pollsKeys[index];
return result; // make sure the filter is still installed after arrival of the request
if(self.polls[key]) {
result.callback = self.polls[key].callback;
return result;
} else
return false;
}).filter(function (result) {
return (!result) ? false : true;
}).filter(function (result) { }).filter(function (result) {
var valid = Jsonrpc.getInstance().isValidResponse(result); var valid = Jsonrpc.getInstance().isValidResponse(result);
if (!valid) { if (!valid) {
@ -4130,11 +4245,11 @@ var eth = function () {
switch(type) { switch(type) {
case 'latest': case 'latest':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newBlockFilter'; return 'eth_newBlockFilter';
case 'pending': case 'pending':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newPendingTransactionFilter'; return 'eth_newPendingTransactionFilter';
default: default:

20
dist/web3.js.map vendored

File diff suppressed because one or more lines are too long

6
dist/web3.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -11,92 +11,193 @@
var from = web3.eth.coinbase; var from = web3.eth.coinbase;
web3.eth.defaultAccount = from; web3.eth.defaultAccount = from;
/* var nameregAbi = [
window.onload = function () { {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},
var abi = [{ {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},
"anonymous" : false, {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},
"inputs" : [ {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},
{ {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},
"indexed" : true, {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},
"name" : "from", {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},
"type" : "address" {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},
}, {"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},
{ {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},
"indexed" : true, {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},
"name" : "to", {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},
"type" : "bytes32" {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},
}, {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},
{ {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}
"indexed" : false, ];
"name" : "value",
"type" : "uint256"
}
],
"name" : "Deposit",
"type" : "event"
}];
var ExchangeInterface = web3.eth.contract(abi).at(web3.eth.namereg.addr('XROO')); var depositAbi = [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"deposit","outputs":[],"type":"function"}];
var filter = ExchangeInterface.Deposit({}, {fromBlock: 0});
filter.watch(function (err, event) { var Namereg = web3.eth.contract(nameregAbi);
console.log(event); var Deposit = web3.eth.contract(depositAbi);
displayDeposit("block: " + event.blockNumber + " user: " + event.args._id + "\nvalue : " + event.args._value.toString(10));
}); var namereg = web3.eth.namereg;
var deposit;
var iban;
function validateNamereg() {
var address = document.getElementById('namereg').value;
var ok = /^(0x)?[0-9a-f]{40}$/.test(address) || address === 'default';
if (ok) {
namereg = address === 'default' ? web3.eth.namereg : Namereg.at(address);
document.getElementById('nameregValidation').innerText = 'ok!';
} else {
document.getElementById('nameregValidation').innerText = 'namereg address is incorrect!';
}
return ok;
}; };
*/
function displayDeposit(text) { function onNameregKeyUp() {
var node = document.createElement('li'); updateIBAN(validateNamereg());
var textnode = document.createTextNode(text); onExchangeKeyUp();
node.appendChild(textnode); };
document.getElementById('deposits').appendChild(node);
} function validateExchange() {
var exchange = document.getElementById('exchange').value;
var ok = /^[0-9A-Z]{4}$/.test(exchange);
if (ok) {
var address = namereg.addr(exchange);
deposit = Deposit.at(address);
document.getElementById('exchangeValidation').innerText = 'ok! address of exchange: ' + address;
} else {
document.getElementById('exchangeValidation').innerText = 'exchange id is incorrect';
}
return ok;
};
function onExchangeKeyUp() {
updateIBAN(validateExchange());
};
function validateClient() {
var client = document.getElementById('client').value;
var ok = /^[0-9A-Z]{9}$/.test(client);
if (ok) {
document.getElementById('clientValidation').innerText = 'ok!';
} else {
document.getElementById('clientValidation').innerText = 'client id is incorrect';
}
return ok;
};
function onClientKeyUp() {
updateIBAN(validateClient());
};
function validateValue() { function validateValue() {
try { try {
var value = document.getElementById('value').value; var value = document.getElementById('value').value;
var bnValue = new BigNumber(value); var bnValue = new BigNumber(value);
document.getElementById('valueValidation').innerText = bnValue.toString(10); document.getElementById('valueValidation').innerText = bnValue.toString(10);
return true;
} catch (err) { } catch (err) {
document.getElementById('valueValidation').innerText = 'Value is incorrect, cannot parse'; document.getElementById('valueValidation').innerText = 'Value is incorrect, cannot parse';
return false;
} }
}; };
function onValueKeyUp() {
validateValue();
};
function validateIBAN() { function validateIBAN() {
var iban = document.getElementById('iban').value;
if (!web3.isIBAN(iban)) { if (!web3.isIBAN(iban)) {
return document.getElementById('ibanValidation').innerText = 'IBAN number is incorrect'; return document.getElementById('ibanValidation').innerText = ' - IBAN number is incorrect';
} }
var institution = iban.substr(7, 4); document.getElementById('ibanValidation').innerText = ' - IBAN number correct';
var address = web3.eth.namereg.addr(institution); };
document.getElementById('ibanValidation').innerText = 'IBAN number correct, exchange address: ' + address;
function updateIBAN(ok) {
var exchangeId = document.getElementById('exchange').value;
var clientId = document.getElementById('client').value;
iban = 'XE' + '00' + 'ETH' + exchangeId + clientId;
document.getElementById('iban').innerText = iban;
validateIBAN();
}; };
function transfer() { function transfer() {
var value = new BigNumber(document.getElementById('value').value); var value = new BigNumber(document.getElementById('value').value);
var iban = document.getElementById('iban').value; var exchange = document.getElementById('exchange').value;
web3.eth.sendIBANTransaction(from, iban, value); var client = document.getElementById('client').value;
deposit.deposit(client, {value: value});
displayTransfer("deposited client's " + client + " funds " + value.toString(10) + " to exchange " + exchange);
}; };
function displayTransfer(text) {
var node = document.createElement('li');
var textnode = document.createTextNode(text);
node.appendChild(textnode);
document.getElementById('transfers').appendChild(node);
}
</script> </script>
</head> </head>
<body> <body>
<h1>ICAP</h1> <h1>ICAP transfer</h1>
<h3>Transfer</h3>
<div> <div>
<text>Destination IBAN (eg. XE81ETHXROOGAVOFYORK): </text> <h4>namereg address</h4>
<input type="text" id="iban" onkeyup='validateIBAN()'></input>
<text id="ibanValidation"></text>
</div> </div>
<div> <div>
<text>Value: </text> <text>eg. 0x436474facc88948696b371052a1befb801f003ca or 'default')</text>
<input type="text" id="value" onkeyup='validateValue()'></input> </div>
<div>
<input type="text" id="namereg" onkeyup='onNameregKeyUp()' value="default"></input>
<text id="nameregValidation"></text>
</div>
<div>
<h4>exchange identifier</h4>
</div>
<div>
<text>eg. WYWY</text>
</div>
<div>
<input type="text" id="exchange" onkeyup='onExchangeKeyUp()'></input>
<text id="exchangeValidation"></text>
</div>
<div>
<h4>client identifier</h4>
</div>
<div>
<text>eg. GAVOFYORK</text>
</div>
<div>
<input type="text" id="client" onkeyup='onClientKeyUp()'></input>
<text id="clientValidation"></text>
</div>
<div>
<h4>value</h4>
</div>
<div>
<text>eg. 100</text>
</div>
<div>
<input type="text" id="value" onkeyup='onValueKeyUp()'></input>
<text id="valueValidation"></text> <text id="valueValidation"></text>
</div> </div>
<div>&nbsp;</div>
<div>
<text>IBAN: </text>
<text id="iban"></text>
<text id="ibanValidation"></text>
</div>
<div>&nbsp;</div>
<div> <div>
<button id="transfer" type="button" onClick="transfer()">Transfer!</button> <button id="transfer" type="button" onClick="transfer()">Transfer!</button>
<text id="transferValidation"></text>
</div>
<div>
<h4>transfers</h4>
</div>
<div>
<ul id='transfers'></ul>
</div> </div>
<h3 style="visibility: hidden;">"XREG" Exchange deposits</h3>
<ul style="visibility: hidden;" id="deposits"></ul>
</body> </body>
</html> </html>

View File

@ -38,11 +38,19 @@ var BigNumber = require('bignumber.js');
var ETH_UNITS = [ var ETH_UNITS = [
'wei', 'wei',
'Kwei', 'kwei',
'Mwei', 'Mwei',
'Gwei', 'Gwei',
'szabo', 'szabo',
'finney', 'finney',
'femtoether',
'picoether',
'nanoether',
'microether',
'milliether',
'nano',
'micro',
'milli',
'ether', 'ether',
'grand', 'grand',
'Mether', 'Mether',
@ -63,7 +71,7 @@ module.exports = {
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS, ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000, ETH_POLLING_TIMEOUT: 1000/2,
defaultBlock: 'latest', defaultBlock: 'latest',
defaultAccount: undefined defaultAccount: undefined
}; };

View File

@ -36,22 +36,30 @@
var BigNumber = require('bignumber.js'); var BigNumber = require('bignumber.js');
var unitMap = { var unitMap = {
'wei': '1', 'wei': '1',
'kwei': '1000', 'kwei': '1000',
'ada': '1000', 'ada': '1000',
'mwei': '1000000', 'femtoether': '1000',
'babbage': '1000000', 'mwei': '1000000',
'gwei': '1000000000', 'babbage': '1000000',
'shannon': '1000000000', 'picoether': '1000000',
'szabo': '1000000000000', 'gwei': '1000000000',
'finney': '1000000000000000', 'shannon': '1000000000',
'ether': '1000000000000000000', 'nanoether': '1000000000',
'kether': '1000000000000000000000', 'nano': '1000000000',
'grand': '1000000000000000000000', 'szabo': '1000000000000',
'einstein': '1000000000000000000000', 'microether': '1000000000000',
'mether': '1000000000000000000000000', 'micro': '1000000000000',
'gether': '1000000000000000000000000000', 'finney': '1000000000000000',
'tether': '1000000000000000000000000000000' 'milliether': '1000000000000000',
'milli': '1000000000000000',
'ether': '1000000000000000000',
'kether': '1000000000000000000000',
'grand': '1000000000000000000000',
'einstein': '1000000000000000000000',
'mether': '1000000000000000000000000',
'gether': '1000000000000000000000000000',
'tether': '1000000000000000000000000000000'
}; };
/** /**
@ -250,13 +258,14 @@ var getValueOfUnit = function (unit) {
* Takes a number of wei and converts it to any other ether unit. * Takes a number of wei and converts it to any other ether unit.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether
@ -276,13 +285,14 @@ var fromWei = function(number, unit) {
* Takes a number of a unit and converts it to wei. * Takes a number of a unit and converts it to wei.
* *
* Possible units are: * Possible units are:
* - kwei/ada * SI Short SI Full Effigy Other
* - mwei/babbage * - kwei femtoether ada
* - gwei/shannon * - mwei picoether babbage
* - szabo * - gwei nanoether shannon nano
* - finney * - -- microether szabo micro
* - ether * - -- milliether finney milli
* - kether/grand/einstein * - ether -- --
* - kether einstein grand
* - mether * - mether
* - gether * - gether
* - tether * - tether

View File

@ -93,8 +93,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) {
return fil(eventParams, options); return fil(eventParams, options);
} }
// what outputLogFormatter? that's wrong // output logs works for blockFilter and pendingTransaction filters?
//return new Filter(fil, watches.eth(), formatters.outputLogFormatter);
return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -149,6 +148,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', {
} }
}); });
// EXTEND
web3._extend = function(extension){
/*jshint maxcomplexity: 6 */
if(extension.property && !web3[extension.property])
web3[extension.property] = {};
setupMethods(web3[extension.property] || web3, extension.methods || []);
setupProperties(web3[extension.property] || web3, extension.properties || []);
};
web3._extend.formatters = formatters;
web3._extend.utils = utils;
web3._extend.Method = require('./web3/method');
web3._extend.Property = require('./web3/property');
/// setups all api methods /// setups all api methods
setupProperties(web3, web3Properties); setupProperties(web3, web3Properties);
setupMethods(web3.net, net.methods); setupMethods(web3.net, net.methods);

View File

@ -74,21 +74,36 @@ var getOptions = function (options) {
}; };
}; };
var Filter = function (options, methods, formatter) { /**
var implementation = {}; Adds the callback and sets up the methods, to iterate over the results.
methods.forEach(function (method) {
method.attachToObject(implementation); @method getLogsAtStart
}); @param {Object} self
this.options = getOptions(options); @param {funciton}
this.implementation = implementation; */
this.callbacks = []; var getLogsAtStart = function(self, callback){
this.formatter = formatter; // call getFilterLogs for the first watch callback start
this.filterId = this.implementation.newFilter(this.options); if (!utils.isString(self.options)) {
self.get(function (err, messages) {
// don't send all the responses to all the watches again... just to self one
if (err) {
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
});
});
}
}; };
Filter.prototype.watch = function (callback) { /**
this.callbacks.push(callback); Adds the callback and sets up the methods, to iterate over the results.
var self = this;
@method pollFilter
@param {Object} self
*/
var pollFilter = function(self) {
var onMessage = function (error, messages) { var onMessage = function (error, messages) {
if (error) { if (error) {
@ -105,29 +120,55 @@ Filter.prototype.watch = function (callback) {
}); });
}; };
// call getFilterLogs on start RequestManager.getInstance().startPolling({
if (!utils.isString(this.options)) { method: self.implementation.poll.call,
this.get(function (err, messages) { params: [self.filterId],
// don't send all the responses to all the watches again... just to this one }, self.filterId, onMessage, self.stopWatching.bind(self));
if (err) {
callback(err);
}
messages.forEach(function (message) { };
callback(null, message);
var Filter = function (options, methods, formatter) {
var self = this;
var implementation = {};
methods.forEach(function (method) {
method.attachToObject(implementation);
});
this.options = getOptions(options);
this.implementation = implementation;
this.callbacks = [];
this.pollFilters = [];
this.formatter = formatter;
this.implementation.newFilter(this.options, function(error, id){
if(error) {
self.callbacks.forEach(function(callback){
callback(error);
}); });
}); } else {
self.filterId = id;
// get filter logs at start
self.callbacks.forEach(function(callback){
getLogsAtStart(self, callback);
});
pollFilter(self);
}
});
};
Filter.prototype.watch = function (callback) {
this.callbacks.push(callback);
if(this.filterId) {
getLogsAtStart(this, callback);
pollFilter(this);
} }
RequestManager.getInstance().startPolling({ return this;
method: this.implementation.poll.call,
params: [this.filterId],
}, this.filterId, onMessage, this.stopWatching.bind(this));
}; };
Filter.prototype.stopWatching = function () { Filter.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.filterId); RequestManager.getInstance().stopPolling(this.filterId);
this.implementation.uninstallFilter(this.filterId); // remove filter async
this.implementation.uninstallFilter(this.filterId, function(){});
this.callbacks = []; this.callbacks = [];
}; };
@ -149,6 +190,8 @@ Filter.prototype.get = function (callback) {
return self.formatter ? self.formatter(log) : log; return self.formatter ? self.formatter(log) : log;
}); });
} }
return this;
}; };
module.exports = Filter; module.exports = Filter;

View File

@ -89,8 +89,10 @@ var inputTransactionFormatter = function (options){
* @returns {Object} transaction * @returns {Object} transaction
*/ */
var outputTransactionFormatter = function (tx){ var outputTransactionFormatter = function (tx){
tx.blockNumber = utils.toDecimal(tx.blockNumber); if(tx.blockNumber !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.blockNumber = utils.toDecimal(tx.blockNumber);
if(tx.transactionIndex !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.nonce = utils.toDecimal(tx.nonce); tx.nonce = utils.toDecimal(tx.nonce);
tx.gas = utils.toDecimal(tx.gas); tx.gas = utils.toDecimal(tx.gas);
tx.gasPrice = utils.toBigNumber(tx.gasPrice); tx.gasPrice = utils.toBigNumber(tx.gasPrice);
@ -112,7 +114,8 @@ var outputBlockFormatter = function(block) {
block.gasUsed = utils.toDecimal(block.gasUsed); block.gasUsed = utils.toDecimal(block.gasUsed);
block.size = utils.toDecimal(block.size); block.size = utils.toDecimal(block.size);
block.timestamp = utils.toDecimal(block.timestamp); block.timestamp = utils.toDecimal(block.timestamp);
block.number = utils.toDecimal(block.number); if(block.number !== null)
block.number = utils.toDecimal(block.number);
block.difficulty = utils.toBigNumber(block.difficulty); block.difficulty = utils.toBigNumber(block.difficulty);
block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
@ -139,9 +142,12 @@ var outputLogFormatter = function(log) {
return null; return null;
} }
log.blockNumber = utils.toDecimal(log.blockNumber); if(log.blockNumber !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex); log.blockNumber = utils.toDecimal(log.blockNumber);
log.logIndex = utils.toDecimal(log.logIndex); if(log.transactionIndex !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex);
if(log.logIndex !== null)
log.logIndex = utils.toDecimal(log.logIndex);
return log; return log;
}; };

View File

@ -23,6 +23,7 @@
var web3 = require('../web3'); var web3 = require('../web3');
var coder = require('../solidity/coder'); var coder = require('../solidity/coder');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var formatters = require('./formatters');
var sha3 = require('../utils/sha3'); var sha3 = require('../utils/sha3');
/** /**
@ -46,6 +47,12 @@ SolidityFunction.prototype.extractCallback = function (args) {
} }
}; };
SolidityFunction.prototype.extractDefaultBlock = function (args) {
if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {
return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array!
}
};
/** /**
* Should be used to create payload from arguments * Should be used to create payload from arguments
* *
@ -97,15 +104,17 @@ SolidityFunction.prototype.unpackOutput = function (output) {
SolidityFunction.prototype.call = function () { SolidityFunction.prototype.call = function () {
var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });
var callback = this.extractCallback(args); var callback = this.extractCallback(args);
var defaultBlock = this.extractDefaultBlock(args);
var payload = this.toPayload(args); var payload = this.toPayload(args);
if (!callback) { if (!callback) {
var output = web3.eth.call(payload); var output = web3.eth.call(payload, defaultBlock);
return this.unpackOutput(output); return this.unpackOutput(output);
} }
var self = this; var self = this;
web3.eth.call(payload, function (error, output) { web3.eth.call(payload, defaultBlock, function (error, output) {
callback(error, self.unpackOutput(output)); callback(error, self.unpackOutput(output));
}); });
}; };

View File

@ -35,6 +35,7 @@ HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -78,6 +79,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}; };
request.open('POST', this.host, true); request.open('POST', this.host, true);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));

View File

@ -43,9 +43,9 @@ var RequestManager = function (provider) {
arguments.callee._singletonInstance = this; arguments.callee._singletonInstance = this;
this.provider = provider; this.provider = provider;
this.polls = []; this.polls = {};
this.timeout = null; this.timeout = null;
this.poll(); this.isPolling = false;
}; };
/** /**
@ -140,6 +140,11 @@ RequestManager.prototype.sendBatch = function (data, callback) {
*/ */
RequestManager.prototype.setProvider = function (p) { RequestManager.prototype.setProvider = function (p) {
this.provider = p; this.provider = p;
if(this.provider && !this.isPolling) {
this.poll();
this.isPolling = true;
}
}; };
/*jshint maxparams:4 */ /*jshint maxparams:4 */
@ -156,7 +161,7 @@ RequestManager.prototype.setProvider = function (p) {
* @todo cleanup number of params * @todo cleanup number of params
*/ */
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -167,24 +172,21 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst
* @param {Number} pollId * @param {Number} pollId
*/ */
RequestManager.prototype.stopPolling = function (pollId) { RequestManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) { delete this.polls['poll_'+ pollId];
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
}; };
/** /**
* Should be called to reset polling mechanism of request manager * Should be called to reset the polling mechanism of the request manager
* *
* @method reset * @method reset
*/ */
RequestManager.prototype.reset = function () { RequestManager.prototype.reset = function () {
this.polls.forEach(function (poll) { for (var key in this.polls) {
poll.uninstall(poll.id); if (this.polls.hasOwnProperty(key)) {
}); this.polls[key].uninstall();
this.polls = []; }
}
this.polls = {};
if (this.timeout) { if (this.timeout) {
clearTimeout(this.timeout); clearTimeout(this.timeout);
@ -199,9 +201,10 @@ RequestManager.prototype.reset = function () {
* @method poll * @method poll
*/ */
RequestManager.prototype.poll = function () { RequestManager.prototype.poll = function () {
/*jshint maxcomplexity: 6 */
this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);
if (!this.polls.length) { if (this.polls === {}) {
return; return;
} }
@ -210,9 +213,20 @@ RequestManager.prototype.poll = function () {
return; return;
} }
var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { var pollsData = [];
return data.data; var pollsKeys = [];
})); for (var key in this.polls) {
if (this.polls.hasOwnProperty(key)) {
pollsData.push(this.polls[key].data);
pollsKeys.push(key);
}
}
if (pollsData.length === 0) {
return;
}
var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);
var self = this; var self = this;
this.provider.sendAsync(payload, function (error, results) { this.provider.sendAsync(payload, function (error, results) {
@ -226,8 +240,15 @@ RequestManager.prototype.poll = function () {
} }
results.map(function (result, index) { results.map(function (result, index) {
result.callback = self.polls[index].callback; var key = pollsKeys[index];
return result; // make sure the filter is still installed after arrival of the request
if(self.polls[key]) {
result.callback = self.polls[key].callback;
return result;
} else
return false;
}).filter(function (result) {
return (!result) ? false : true;
}).filter(function (result) { }).filter(function (result) {
var valid = Jsonrpc.getInstance().isValidResponse(result); var valid = Jsonrpc.getInstance().isValidResponse(result);
if (!valid) { if (!valid) {

View File

@ -29,11 +29,11 @@ var eth = function () {
switch(type) { switch(type) {
case 'latest': case 'latest':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newBlockFilter'; return 'eth_newBlockFilter';
case 'pending': case 'pending':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newPendingTransactionFilter'; return 'eth_newPendingTransactionFilter';
default: default:

View File

@ -66,7 +66,7 @@ describe('web3.eth.contract', function () {
provider.injectValidation(function (payload) { provider.injectValidation(function (payload) {
if (step === 0) { if (step === 0) {
step = 1; step = 1;
provider.injectResult(3); provider.injectResult('0x3');
assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_newFilter'); assert.equal(payload.method, 'eth_newFilter');
assert.deepEqual(payload.params[0], { assert.deepEqual(payload.params[0], {
@ -105,7 +105,7 @@ describe('web3.eth.contract', function () {
'0000000000000000000000000000000000000000000000000000000000000008' '0000000000000000000000000000000000000000000000000000000000000008'
}]]); }]]);
var r = payload.filter(function (p) { var r = payload.filter(function (p) {
return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === 3; return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === '0x3';
}); });
assert.equal(r.length > 0, true); assert.equal(r.length > 0, true);
} }
@ -114,7 +114,8 @@ describe('web3.eth.contract', function () {
var contract = web3.eth.contract(desc).at(address); var contract = web3.eth.contract(desc).at(address);
var res = 0; var res = 0;
contract.Changed({from: address}).watch(function(err, result) { var event = contract.Changed({from: address});
event.watch(function(err, result) {
assert.equal(result.args.from, address); assert.equal(result.args.from, address);
assert.equal(result.args.amount, 1); assert.equal(result.args.amount, 1);
assert.equal(result.args.t1, 1); assert.equal(result.args.t1, 1);
@ -133,6 +134,7 @@ describe('web3.eth.contract', function () {
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)' var signature = 'balance(address)'
var address = '0x1234567890123456789012345678901234567890'; var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) { provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call'); assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{ assert.deepEqual(payload.params, [{
@ -147,6 +149,28 @@ describe('web3.eth.contract', function () {
assert.deepEqual(new BigNumber(0x32), r); assert.deepEqual(new BigNumber(0x32), r);
}); });
it('should call constant function with default block', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)'
var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address
}, '0xb']);
});
var contract = web3.eth.contract(desc).at(address);
var r = contract.balance(address, 11);
assert.deepEqual(new BigNumber(0x32), r);
});
it('should sendTransaction to contract function', function () { it('should sendTransaction to contract function', function () {
var provider = new FakeHttpProvider(); var provider = new FakeHttpProvider();
web3.setProvider(provider); web3.setProvider(provider);
@ -218,6 +242,31 @@ describe('web3.eth.contract', function () {
}); });
it('should explicitly make a call with optional params and defaultBlock', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)';
var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address,
from: address,
gas: '0xc350'
}, '0xb']);
});
var contract = web3.eth.contract(desc).at(address);
var r = contract.balance.call(address, {from: address, gas: 50000}, 11);
assert.deepEqual(new BigNumber(0x32), r);
});
it('should sendTransaction with optional params', function () { it('should sendTransaction with optional params', function () {
var provider = new FakeHttpProvider(); var provider = new FakeHttpProvider();
web3.setProvider(provider); web3.setProvider(provider);

View File

@ -8,38 +8,72 @@ describe('formatters', function () {
it('should return the correct value', function () { it('should return the correct value', function () {
assert.deepEqual(formatters.outputBlockFormatter({ assert.deepEqual(formatters.outputBlockFormatter({
hash: '0x34234kjh23kj4234', hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
parentHash: '0x34234kjh23kj4234', parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: '0x34234kjh23kj4234', miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf',
stateRoot: '0x34234kjh23kj4234', stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x34234kjh23kj4234', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0x34234kjh23kj4234', bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: '0x3e8', difficulty: '0x3e8',
totalDifficulty: '0x3e8', totalDifficulty: '0x3e8',
number: '0x3e8', number: '0x3e8',
gasLimit: '0x3e8', gasLimit: '0x3e8',
gasUsed: '0x3e8', gasUsed: '0x3e8',
timestamp: '0x3e8', timestamp: '0x3e8',
extraData: '0x34234kjh23kj4234', extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: '0x34234kjh23kj4234', nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
children: ['0x34234kjh23kj4234'],
size: '0x3e8' size: '0x3e8'
}), { }), {
hash: '0x34234kjh23kj4234', hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
parentHash: '0x34234kjh23kj4234', parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: '0x34234kjh23kj4234', miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf',
stateRoot: '0x34234kjh23kj4234', stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x34234kjh23kj4234', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0x34234kjh23kj4234', bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: new BigNumber(1000), difficulty: new BigNumber(1000),
totalDifficulty: new BigNumber(1000), totalDifficulty: new BigNumber(1000),
number: 1000, number: 1000,
gasLimit: 1000, gasLimit: 1000,
gasUsed: 1000, gasUsed: 1000,
timestamp: 1000, timestamp: 1000,
extraData: '0x34234kjh23kj4234', extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: '0x34234kjh23kj4234', nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
children: ['0x34234kjh23kj4234'], size: 1000
});
});
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputBlockFormatter({
hash: null,
parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: null,
stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: '0x3e8',
totalDifficulty: '0x3e8',
number: null,
gasLimit: '0x3e8',
gasUsed: '0x3e8',
timestamp: '0x3e8',
extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: null,
size: '0x3e8'
}), {
hash: null,
parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: null,
stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: new BigNumber(1000),
totalDifficulty: new BigNumber(1000),
number: null,
gasLimit: 1000,
gasUsed: 1000,
timestamp: 1000,
extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: null,
size: 1000 size: 1000
}); });
}); });

View File

@ -9,17 +9,37 @@ describe('formatters', function () {
transactionIndex: '0x3e8', transactionIndex: '0x3e8',
logIndex: '0x3e8', logIndex: '0x3e8',
blockNumber: '0x3e8', blockNumber: '0x3e8',
transactionHash: '0x7b2274657374223a2274657374227d', transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
blockHash: '0x7b2274657374223a2274657374227d', blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
data: '0x7b2274657374223a2274657374227d', data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373'] topics: ['0x68656c6c6f','0x6d79746f70696373']
}), { }), {
transactionIndex: 1000, transactionIndex: 1000,
logIndex: 1000, logIndex: 1000,
blockNumber: 1000, blockNumber: 1000,
transactionHash: '0x7b2274657374223a2274657374227d', transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
blockHash: '0x7b2274657374223a2274657374227d', blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
data: '0x7b2274657374223a2274657374227d', data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373']
});
});
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputLogFormatter({
transactionIndex: null,
logIndex: null,
blockNumber: null,
transactionHash: null,
blockHash: null,
data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373']
}), {
transactionIndex: null,
logIndex: null,
blockNumber: null,
transactionHash: null,
blockHash: null,
data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373'] topics: ['0x68656c6c6f','0x6d79746f70696373']
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('formatters', function () {
it('should return the correct value', function () { it('should return the correct value', function () {
assert.deepEqual(formatters.outputTransactionFormatter({ assert.deepEqual(formatters.outputTransactionFormatter({
input: '0x34234kjh23kj4234', input: '0x3454645634534',
from: '0x00000', from: '0x00000',
to: '0x00000', to: '0x00000',
value: '0x3e8', value: '0x3e8',
@ -16,9 +16,9 @@ describe('formatters', function () {
nonce: '0xb', nonce: '0xb',
transactionIndex: '0x1', transactionIndex: '0x1',
blockNumber: '0x3e8', blockNumber: '0x3e8',
blockHash: '0x34234bf23bf4234' blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9'
}), { }), {
input: '0x34234kjh23kj4234', input: '0x3454645634534',
from: '0x00000', from: '0x00000',
to: '0x00000', to: '0x00000',
value: new BigNumber(1000), value: new BigNumber(1000),
@ -26,9 +26,36 @@ describe('formatters', function () {
gasPrice: new BigNumber(1000), gasPrice: new BigNumber(1000),
nonce: 11, nonce: 11,
blockNumber: 1000, blockNumber: 1000,
blockHash: '0x34234bf23bf4234', blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9',
transactionIndex: 1 transactionIndex: 1
}); });
}); });
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputTransactionFormatter({
input: '0x3454645634534',
from: '0x00000',
to: null,
value: '0x3e8',
gas: '0x3e8',
gasPrice: '0x3e8',
nonce: '0xb',
transactionIndex: null,
blockNumber: null,
blockHash: null
}), {
input: '0x3454645634534',
from: '0x00000',
to: null,
value: new BigNumber(1000),
gas: 1000,
gasPrice: new BigNumber(1000),
nonce: 11,
blockNumber: null,
blockHash: null,
transactionIndex: null
});
});
}); });
}); });

View File

@ -15,11 +15,21 @@ FakeHttpProvider2.prototype.injectResultList = function (list) {
FakeHttpProvider2.prototype.getResponse = function () { FakeHttpProvider2.prototype.getResponse = function () {
var result = this.resultList[this.counter]; var result = this.resultList[this.counter];
this.counter++; this.counter++;
// add fallback result value
if(!result)
result = {
result: undefined
};
if (result.type === 'batch') { if (result.type === 'batch') {
this.injectBatchResults(result.result); this.injectBatchResults(result.result);
} else { } else {
this.injectResult(result.result); this.injectResult(result.result);
} }
this.counter = 0;
return this.response; return this.response;
}; };

View File

@ -6,6 +6,9 @@ var FakeXMLHttpRequest = function () {
this.readyState = 4; this.readyState = 4;
this.onreadystatechange = null; this.onreadystatechange = null;
this.async = false; this.async = false;
this.headers = {
'Content-Type': 'text/plain'
};
}; };
FakeXMLHttpRequest.prototype.open = function (method, host, async) { FakeXMLHttpRequest.prototype.open = function (method, host, async) {
@ -15,6 +18,10 @@ FakeXMLHttpRequest.prototype.open = function (method, host, async) {
this.async = async; this.async = async;
}; };
FakeXMLHttpRequest.prototype.setRequestHeader = function(name, value) {
this.headers[name] = value;
};
FakeXMLHttpRequest.prototype.send = function (payload) { FakeXMLHttpRequest.prototype.send = function (payload) {
assert.equal(typeof payload, 'string'); assert.equal(typeof payload, 'string');
if (this.async) { if (this.async) {

View File

@ -19,6 +19,14 @@ describe('lib/utils/utils', function () {
assert.equal(utils.toWei(1, 'gether'), '1000000000000000000000000000'); assert.equal(utils.toWei(1, 'gether'), '1000000000000000000000000000');
assert.equal(utils.toWei(1, 'tether'), '1000000000000000000000000000000'); assert.equal(utils.toWei(1, 'tether'), '1000000000000000000000000000000');
assert.equal(utils.toWei(1, 'kwei'), utils.toWei(1, 'femtoether'));
assert.equal(utils.toWei(1, 'babbage'), utils.toWei(1, 'picoether'));
assert.equal(utils.toWei(1, 'shannon'), utils.toWei(1, 'nanoether'));
assert.equal(utils.toWei(1, 'szabo'), utils.toWei(1, 'microether'));
assert.equal(utils.toWei(1, 'finney'), utils.toWei(1, 'milliether'));
assert.equal(utils.toWei(1, 'milli'), utils.toWei(1, 'milliether'));
assert.equal(utils.toWei(1, 'milli'), utils.toWei(1000, 'micro'));
assert.throws(function () {utils.toWei(1, 'wei1');}, Error); assert.throws(function () {utils.toWei(1, 'wei1');}, Error);
}); });
}); });

76
test/web3.extend.js Normal file
View File

@ -0,0 +1,76 @@
var chai = require('chai');
var assert = chai.assert;
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var web3 = require('../lib/web3');
var tests = [{
properties: [new web3._extend.Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
},{
methods: [new web3._extend.Method({
name: 'getBalance',
call: 'eth_getBalance',
params: 2,
inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter],
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
},{
property: 'admin',
properties: [new web3._extend.Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})],
methods: [new web3._extend.Method({
name: 'getBalance',
call: 'eth_getBalance',
params: 2,
inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter],
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
}];
describe('web3', function () {
describe('_extend', function () {
tests.forEach(function (test, index) {
it('test no: ' + index, function () {
web3._extend(test);
if(test.properties)
test.properties.forEach(function(property){
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult('');
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, property.getter);
});
if(test.property) {
assert.isObject(web3[test.property][property.name]);
assert.isFunction(web3[test.property]['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]);
} else {
assert.isObject(web3[property.name]);
assert.isFunction(web3['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]);
}
});
if(test.methods)
test.methods.forEach(function(property){
if(test.property)
assert.isFunction(web3[test.property][property.name]);
else
assert.isFunction(web3[property.name]);
});
});
});
});
});