aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/ethereum/main.go17
-rw-r--r--cmd/mist/assets/examples/coin.html9
-rw-r--r--cmd/mist/assets/ext/ethereum.js/dist/ethereum.js2525
-rw-r--r--cmd/utils/flags.go4
-rw-r--r--core/block_processor.go17
-rw-r--r--core/chain_manager.go2
-rw-r--r--core/state_transition.go35
-rw-r--r--javascript/types.go2
-rw-r--r--logger/types.go7
-rw-r--r--miner/worker.go8
-rw-r--r--rpc/api.go700
-rw-r--r--rpc/api_test.go18
-rw-r--r--rpc/args.go539
-rw-r--r--rpc/args_test.go434
-rw-r--r--rpc/messages.go384
-rw-r--r--rpc/responses.go212
-rw-r--r--rpc/util.go74
-rw-r--r--rpc/util_test.go25
-rw-r--r--vm/vm.go8
-rw-r--r--xeth/xeth.go45
20 files changed, 3184 insertions, 1881 deletions
diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go
index 89e19e47f..73c67bdc9 100644
--- a/cmd/ethereum/main.go
+++ b/cmd/ethereum/main.go
@@ -26,6 +26,7 @@ import (
"os"
"runtime"
"strconv"
+ "strings"
"time"
"github.com/codegangsta/cli"
@@ -112,6 +113,7 @@ runtime will execute the file and exit.
},
}
app.Flags = []cli.Flag{
+ utils.UnlockedAccountFlag,
utils.BootnodesFlag,
utils.DataDirFlag,
utils.ListenPortFlag,
@@ -192,6 +194,21 @@ Please run 'ethereum account new' to create a new account.`)
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
utils.StartEthereum(eth)
+
+ // Load startup keys. XXX we are going to need a different format
+ account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
+ if len(account) > 0 {
+ split := strings.Split(account, ":")
+ if len(split) != 2 {
+ utils.Fatalf("Illegal 'unlock' format (address:password)")
+ }
+ am := eth.AccountManager()
+ // Attempt to unlock the account
+ err := am.Unlock(ethutil.Hex2Bytes(split[0]), split[1])
+ if err != nil {
+ utils.Fatalf("Unlock account failed '%v'", err)
+ }
+ }
// Start auxiliary services if enabled.
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
utils.StartRPC(eth, ctx)
diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html
index 509a9aeeb..96f2299a5 100644
--- a/cmd/mist/assets/examples/coin.html
+++ b/cmd/mist/assets/examples/coin.html
@@ -35,7 +35,7 @@
var web3 = require('web3');
var eth = web3.eth;
- web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
+ web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var desc = [{
"name": "balance(address)",
"type": "function",
@@ -72,12 +72,13 @@
// deploy if not exist
if (address == null) {
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
- address = web3.eth.transact({data: code});
+ address = web3.eth.transact({from: eth.coinbase, data: code});
localStorage.setItem("address", address);
}
document.querySelector("#contract_addr").innerHTML = address;
- var contract = web3.eth.contract(address, desc);
+ var Contract = web3.eth.contract(desc);
+ contract = new Contract(address);
contract.Changed({from: eth.coinbase}).changed(function() {
refresh();
});
@@ -88,7 +89,7 @@
var table = document.querySelector("#table_body");
table.innerHTML = ""; // clear
- var storage = eth.storageAt(address);
+ var storage = eth.getStorage(address);
table.innerHTML = "";
for( var item in storage ) {
table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>";
diff --git a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
index 5b7d87270..c0b37641c 100644
--- a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
+++ b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
@@ -22,34 +22,57 @@ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof requ
* @date 2014
*/
-var utils = require('./utils');
+var utils = require('../utils/utils');
+var c = require('../utils/config');
var types = require('./types');
-var c = require('./const');
var f = require('./formatters');
-var displayTypeError = function (type) {
- console.error('parser does not support type: ' + type);
+/**
+ * throw incorrect type error
+ *
+ * @method throwTypeError
+ * @param {String} type
+ * @throws incorrect type error
+ */
+var throwTypeError = function (type) {
+ throw new Error('parser does not support type: ' + type);
};
-/// This method should be called if we want to check if givent type is an array type
-/// @returns true if it is, otherwise false
-var arrayType = function (type) {
+/** This method should be called if we want to check if givent type is an array type
+ *
+ * @method isArrayType
+ * @param {String} type name
+ * @returns {Boolean} true if it is, otherwise false
+ */
+var isArrayType = function (type) {
return type.slice(-2) === '[]';
};
+/**
+ * This method should be called to return dynamic type length in hex
+ *
+ * @method dynamicTypeBytes
+ * @param {String} type
+ * @param {String|Array} dynamic type
+ * @return {String} length of dynamic type in hex or empty string if type is not dynamic
+ */
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
- if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
+ if (isArrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return f.formatInputInt(value.length);
return "";
};
var inputTypes = types.inputTypes();
-/// Formats input params to bytes
-/// @param abi contract method inputs
-/// @param array of params that will be formatted to bytes
-/// @returns bytes representation of input params
+/**
+ * Formats input params to bytes
+ *
+ * @method formatInput
+ * @param {Array} abi inputs of method
+ * @param {Array} params that will be formatted to bytes
+ * @returns bytes representation of input params
+ */
var formatInput = function (inputs, params) {
var bytes = "";
var toAppendConstant = "";
@@ -67,12 +90,12 @@ var formatInput = function (inputs, params) {
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
}
if (!typeMatch) {
- displayTypeError(inputs[i].type);
+ throwTypeError(inputs[i].type);
}
var formatter = inputTypes[j - 1].format;
- if (arrayType(inputs[i].type))
+ if (isArrayType(inputs[i].type))
toAppendArrayContent += params[i].reduce(function (acc, curr) {
return acc + formatter(curr);
}, "");
@@ -87,18 +110,29 @@ var formatInput = function (inputs, params) {
return bytes;
};
+/**
+ * This method should be called to predict the length of dynamic type
+ *
+ * @method dynamicBytesLength
+ * @param {String} type
+ * @returns {Number} length of dynamic type, 0 or multiplication of ETH_PADDING (32)
+ */
var dynamicBytesLength = function (type) {
- if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
+ if (isArrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return c.ETH_PADDING * 2;
return 0;
};
var outputTypes = types.outputTypes();
-/// Formats output bytes back to param list
-/// @param contract abi method outputs
-/// @param bytes representtion of output
-/// @returns array of output params
+/**
+ * Formats output bytes back to param list
+ *
+ * @method formatOutput
+ * @param {Array} abi outputs of method
+ * @param {String} bytes represention of output
+ * @returns {Array} output params
+ */
var formatOutput = function (outs, output) {
output = output.slice(2);
@@ -120,11 +154,11 @@ var formatOutput = function (outs, output) {
}
if (!typeMatch) {
- displayTypeError(outs[i].type);
+ throwTypeError(outs[i].type);
}
var formatter = outputTypes[j - 1].format;
- if (arrayType(outs[i].type)) {
+ if (isArrayType(outs[i].type)) {
var size = f.formatOutputUInt(dynamicPart.slice(0, padding));
dynamicPart = dynamicPart.slice(padding);
var array = [];
@@ -147,9 +181,14 @@ var formatOutput = function (outs, output) {
return result;
};
-/// @param json abi for contract
-/// @returns input parser object for given json abi
-/// TODO: refactor creating the parser, do not double logic from contract
+/**
+ * Should be called to create input parser for contract with given abi
+ *
+ * @method inputParser
+ * @param {Array} contract abi
+ * @returns {Object} input parser object for given json abi
+ * TODO: refactor creating the parser, do not double logic from contract
+ */
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
@@ -171,8 +210,13 @@ var inputParser = function (json) {
return parser;
};
-/// @param json abi for contract
-/// @returns output parser for given json abi
+/**
+ * Should be called to create output parser for contract with given abi
+ *
+ * @method outputParser
+ * @param {Array} contract abi
+ * @returns {Object} output parser for given json abi
+ */
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
@@ -201,7 +245,223 @@ module.exports = {
formatOutput: formatOutput
};
-},{"./const":2,"./formatters":8,"./types":15,"./utils":16}],2:[function(require,module,exports){
+},{"../utils/config":4,"../utils/utils":5,"./formatters":2,"./types":3}],2:[function(require,module,exports){
+/*
+ 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 formatters.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+if ("build" !== 'build') {/*
+ var BigNumber = require('bignumber.js'); // jshint ignore:line
+*/}
+
+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
+ * If the value is floating point, round it down
+ *
+ * @method formatInputInt
+ * @param {String|Number|BigNumber} value that needs to be formatted
+ * @returns {String} right-aligned byte representation of int
+ */
+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);
+};
+
+/**
+ * Formats input value to byte representation of string
+ *
+ * @method formatInputString
+ * @param {String}
+ * @returns {String} left-algined byte representation of string
+ */
+var formatInputString = function (value) {
+ return utils.fromAscii(value, c.ETH_PADDING).substr(2);
+};
+
+/**
+ * Formats input value to byte representation of bool
+ *
+ * @method formatInputBool
+ * @param {Boolean}
+ * @returns {String} right-aligned byte representation bool
+ */
+var formatInputBool = function (value) {
+ return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
+};
+
+/**
+ * Formats input value to byte representation of real
+ * Values are multiplied by 2^m and encoded as integers
+ *
+ * @method formatInputReal
+ * @param {String|Number|BigNumber}
+ * @returns {String} byte representation of real
+ */
+var formatInputReal = function (value) {
+ return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
+};
+
+/**
+ * Check if input value is negative
+ *
+ * @method signedIsNegative
+ * @param {String} value is hex format
+ * @returns {Boolean} true if it is negative, otherwise false
+ */
+var signedIsNegative = function (value) {
+ return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';
+};
+
+/**
+ * Formats right-aligned output bytes to int
+ *
+ * @method formatOutputInt
+ * @param {String} bytes
+ * @returns {BigNumber} right-aligned output bytes formatted to big number
+ */
+var formatOutputInt = function (value) {
+
+ value = value || "0";
+
+ // check if it's negative number
+ // it it is, return two's complement
+ if (signedIsNegative(value)) {
+ return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
+ }
+ return new BigNumber(value, 16);
+};
+
+/**
+ * Formats right-aligned output bytes to uint
+ *
+ * @method formatOutputUInt
+ * @param {String} bytes
+ * @returns {BigNumeber} right-aligned output bytes formatted to uint
+ */
+var formatOutputUInt = function (value) {
+ value = value || "0";
+ return new BigNumber(value, 16);
+};
+
+/**
+ * Formats right-aligned output bytes to real
+ *
+ * @method formatOutputReal
+ * @param {String}
+ * @returns {BigNumber} input bytes formatted to real
+ */
+var formatOutputReal = function (value) {
+ return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128));
+};
+
+/**
+ * Formats right-aligned output bytes to ureal
+ *
+ * @method formatOutputUReal
+ * @param {String}
+ * @returns {BigNumber} input bytes formatted to ureal
+ */
+var formatOutputUReal = function (value) {
+ return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128));
+};
+
+/**
+ * Should be used to format output hash
+ *
+ * @method formatOutputHash
+ * @param {String}
+ * @returns {String} right-aligned output bytes formatted to hex
+ */
+var formatOutputHash = function (value) {
+ return "0x" + value;
+};
+
+/**
+ * Should be used to format output bool
+ *
+ * @method formatOutputBool
+ * @param {String}
+ * @returns {Boolean} right-aligned input bytes formatted to bool
+ */
+var formatOutputBool = function (value) {
+ return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
+};
+
+/**
+ * Should be used to format output string
+ *
+ * @method formatOutputString
+ * @param {Sttring} left-aligned hex representation of string
+ * @returns {String} ascii string
+ */
+var formatOutputString = function (value) {
+ return utils.toAscii(value);
+};
+
+/**
+ * Should be used to format output address
+ *
+ * @method formatOutputAddress
+ * @param {String} right-aligned input bytes
+ * @returns {String} address
+ */
+var formatOutputAddress = function (value) {
+ return "0x" + value.slice(value.length - 40, value.length);
+};
+
+module.exports = {
+ formatInputInt: formatInputInt,
+ formatInputString: formatInputString,
+ formatInputBool: formatInputBool,
+ formatInputReal: formatInputReal,
+ formatOutputInt: formatOutputInt,
+ formatOutputUInt: formatOutputUInt,
+ formatOutputReal: formatOutputReal,
+ formatOutputUReal: formatOutputUReal,
+ formatOutputHash: formatOutputHash,
+ formatOutputBool: formatOutputBool,
+ formatOutputString: formatOutputString,
+ formatOutputAddress: formatOutputAddress
+};
+
+
+},{"../utils/config":4,"../utils/utils":5}],3:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -218,12 +478,106 @@ module.exports = {
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 const.js
+/** @file types.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
+var f = require('./formatters');
+
+/// @param expected type prefix (string)
+/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
+var prefixedType = function (prefix) {
+ return function (type) {
+ return type.indexOf(prefix) === 0;
+ };
+};
+
+/// @param expected type name (string)
+/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
+var namedType = function (name) {
+ return function (type) {
+ return name === type;
+ };
+};
+
+/// Setups input formatters for solidity types
+/// @returns an array of input formatters
+var inputTypes = function () {
+
+ return [
+ { type: prefixedType('uint'), format: f.formatInputInt },
+ { type: prefixedType('int'), format: f.formatInputInt },
+ { type: prefixedType('hash'), format: f.formatInputInt },
+ { type: prefixedType('string'), format: f.formatInputString },
+ { type: prefixedType('real'), format: f.formatInputReal },
+ { type: prefixedType('ureal'), format: f.formatInputReal },
+ { type: namedType('address'), format: f.formatInputInt },
+ { type: namedType('bool'), format: f.formatInputBool }
+ ];
+};
+
+/// Setups output formaters for solidity types
+/// @returns an array of output formatters
+var outputTypes = function () {
+
+ return [
+ { type: prefixedType('uint'), format: f.formatOutputUInt },
+ { type: prefixedType('int'), format: f.formatOutputInt },
+ { type: prefixedType('hash'), format: f.formatOutputHash },
+ { type: prefixedType('string'), format: f.formatOutputString },
+ { type: prefixedType('real'), format: f.formatOutputReal },
+ { type: prefixedType('ureal'), format: f.formatOutputUReal },
+ { type: namedType('address'), format: f.formatOutputAddress },
+ { type: namedType('bool'), format: f.formatOutputBool }
+ ];
+};
+
+module.exports = {
+ prefixedType: prefixedType,
+ namedType: namedType,
+ inputTypes: inputTypes,
+ outputTypes: outputTypes
+};
+
+
+},{"./formatters":2}],4:[function(require,module,exports){
+/*
+ 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 config.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+/**
+ * Utils
+ *
+ * @module utils
+ */
+
+/**
+ * Utility functions
+ *
+ * @class [utils] config
+ * @constructor
+ */
+
/// required to define ETH_BIGNUMBER_ROUNDING_MODE
if ("build" !== 'build') {/*
var BigNumber = require('bignumber.js'); // jshint ignore:line
@@ -256,11 +610,713 @@ module.exports = {
ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
- ETH_POLLING_TIMEOUT: 1000
+ ETH_POLLING_TIMEOUT: 1000,
+ ETH_DEFAULTBLOCK: 'latest'
+};
+
+
+},{}],5:[function(require,module,exports){
+/*
+ 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 utils.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+/**
+ * Utils
+ *
+ * @module utils
+ */
+
+/**
+ * Utility functions
+ *
+ * @class [utils] utils
+ * @constructor
+ */
+
+if ("build" !== 'build') {/*
+ var BigNumber = require('bignumber.js'); // jshint ignore:line
+*/}
+
+var unitMap = {
+ 'wei': '1',
+ 'kwei': '1000',
+ 'ada': '1000',
+ 'mwei': '1000000',
+ 'babbage': '1000000',
+ 'gwei': '1000000000',
+ 'shannon': '1000000000',
+ 'szabo': '1000000000000',
+ 'finney': '1000000000000000',
+ 'ether': '1000000000000000000',
+ 'kether': '1000000000000000000000',
+ 'grand': '1000000000000000000000',
+ 'einstein': '1000000000000000000000',
+ 'mether': '1000000000000000000000000',
+ 'gether': '1000000000000000000000000000',
+ 'tether': '1000000000000000000000000000000'
+};
+
+
+/** Finds first index of array element matching pattern
+ *
+ * @method findIndex
+ * @param {Array}
+ * @param {Function} pattern
+ * @returns {Number} index of element
+ */
+var findIndex = function (array, callback) {
+ var end = false;
+ var i = 0;
+ for (; i < array.length && !end; i++) {
+ end = callback(array[i]);
+ }
+ return end ? i - 1 : -1;
+};
+
+/**
+ * Should be called to get sting from it's hex representation
+ *
+ * @method toAscii
+ * @param {String} string in hex
+ * @returns {String} ascii string representation of hex value
+ */
+var toAscii = function(hex) {
+// Find termination
+ var str = "";
+ var i = 0, l = hex.length;
+ if (hex.substring(0, 2) === '0x') {
+ i = 2;
+ }
+ for (; i < l; i+=2) {
+ var code = parseInt(hex.substr(i, 2), 16);
+ if (code === 0) {
+ break;
+ }
+
+ str += String.fromCharCode(code);
+ }
+
+ return str;
+};
+
+/**
+ * Shold be called to get hex representation (prefixed by 0x) of ascii string
+ *
+ * @method fromAscii
+ * @param {String} string
+ * @returns {String} hex representation of input string
+ */
+var toHexNative = function(str) {
+ var hex = "";
+ for(var i = 0; i < str.length; i++) {
+ var n = str.charCodeAt(i).toString(16);
+ hex += n.length < 2 ? '0' + n : n;
+ }
+
+ return hex;
+};
+
+/**
+ * Shold be called to get hex representation (prefixed by 0x) of ascii string
+ *
+ * @method fromAscii
+ * @param {String} string
+ * @param {Number} optional padding
+ * @returns {String} hex representation of input string
+ */
+var fromAscii = function(str, pad) {
+ pad = pad === undefined ? 0 : pad;
+ var hex = toHexNative(str);
+ while (hex.length < pad*2)
+ hex += "00";
+ return "0x" + hex;
+};
+
+/**
+ * Should be called to get display name of contract function
+ *
+ * @method extractDisplayName
+ * @param {String} name of function/event
+ * @returns {String} display name for function/event eg. multiply(uint256) -> multiply
+ */
+var extractDisplayName = function (name) {
+ var length = name.indexOf('(');
+ return length !== -1 ? name.substr(0, length) : name;
+};
+
+/// @returns overloaded part of function/event name
+var extractTypeName = function (name) {
+ /// TODO: make it invulnerable
+ var length = name.indexOf('(');
+ return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
+};
+
+/**
+ * Filters all functions from input abi
+ *
+ * @method filterFunctions
+ * @param {Array} abi
+ * @returns {Array} abi array with filtered objects of type 'function'
+ */
+var filterFunctions = function (json) {
+ return json.filter(function (current) {
+ return current.type === 'function';
+ });
+};
+
+/**
+ * Filters all events from input abi
+ *
+ * @method filterEvents
+ * @param {Array} abi
+ * @returns {Array} abi array with filtered objects of type 'event'
+ */
+var filterEvents = function (json) {
+ return json.filter(function (current) {
+ return current.type === 'event';
+ });
+};
+
+/**
+ * Converts value to it's decimal representation in string
+ *
+ * @method toDecimal
+ * @param {String|Number|BigNumber}
+ * @return {String}
+ */
+var toDecimal = function (value) {
+ return toBigNumber(value).toNumber();
+};
+
+/**
+ * Converts value to it's hex representation
+ *
+ * @method fromDecimal
+ * @param {String|Number|BigNumber}
+ * @return {String}
+ */
+var fromDecimal = function (value) {
+ var number = toBigNumber(value);
+ var result = number.toString(16);
+
+ return (number.lessThan(0))
+ ? '-0x' + result.substr(1)
+ : '0x' + result;
+};
+
+/**
+ * Auto converts any given value into it's hex representation.
+ *
+ * And even stringifys objects before.
+ *
+ * @method toHex
+ * @param {String|Number|BigNumber|Object}
+ * @return {String}
+ */
+var toHex = function (val) {
+ /*jshint maxcomplexity:5 */
+
+ if(typeof val === 'boolean')
+ return val;
+
+ if(isBigNumber(val))
+ return fromDecimal(val);
+
+ if(typeof val === 'object')
+ return fromAscii(JSON.stringify(val));
+
+ if(isString(val) && val.indexOf('0x') === 0)
+ return val;
+ // if its a negative number, pass it through fromDecimal
+ if(isString(val) && val.indexOf('-0x') === 0)
+ return fromDecimal(val);
+
+ if(isString(val) && !isFinite(val))
+ return fromAscii(val);
+
+ if(isFinite(val))
+ return fromDecimal(val);
+
+ return val;
+};
+
+/**
+ * Returns value of unit in Wei
+ *
+ * @method getValueOfUnit
+ * @param {String} unit the unit to convert to, default ether
+ * @returns {BigNumber} value of the unit (in Wei)
+ * @throws error if the unit is not correct:w
+ */
+var getValueOfUnit = function (unit) {
+ unit = unit ? unit.toLowerCase() : 'ether';
+ var unitValue = unitMap[unit];
+ if (unitValue === undefined) {
+ throw new Error('This unit doesn\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));
+ }
+ return new BigNumber(unitValue, 10);
+};
+
+/**
+ * Takes a number of wei and converts it to any other ether unit.
+ *
+ * Possible units are:
+ * - kwei/ada
+ * - mwei/babbage
+ * - gwei/shannon
+ * - szabo
+ * - finney
+ * - ether
+ * - kether/grand/einstein
+ * - mether
+ * - gether
+ * - tether
+ *
+ * @method fromWei
+ * @param {Number|String} number can be a number, number string or a HEX of a decimal
+ * @param {String} unit the unit to convert to, default ether
+ * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number
+*/
+var fromWei = function(number, unit) {
+ var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));
+
+ return (isBigNumber(number))
+ ? returnValue : returnValue.toString(10);
+};
+
+/**
+ * Takes a number of a unit and converts it to wei.
+ *
+ * Possible units are:
+ * - kwei/ada
+ * - mwei/babbage
+ * - gwei/shannon
+ * - szabo
+ * - finney
+ * - ether
+ * - kether/grand/einstein
+ * - mether
+ * - gether
+ * - tether
+ *
+ * @method toWei
+ * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal
+ * @param {String} unit the unit to convert from, default ether
+ * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number
+*/
+var toWei = function(number, unit) {
+ var returnValue = toBigNumber(number).times(getValueOfUnit(unit));
+
+ return (isBigNumber(number))
+ ? returnValue : returnValue.toString(10);
+};
+
+/**
+ * Takes an input and transforms it into an bignumber
+ *
+ * @method toBigNumber
+ * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber
+ * @return {BigNumber} BigNumber
+*/
+var toBigNumber = function(number) {
+ number = number || 0;
+ if (isBigNumber(number))
+ return number;
+
+ return (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0))
+ ? new BigNumber(number.replace('0x',''), 16)
+ : new BigNumber(number.toString(10), 10);
+};
+
+/**
+ * Takes and input transforms it into bignumber and if it is negative value, into two's complement
+ *
+ * @method toTwosComplement
+ * @param {Number|String|BigNumber}
+ * @return {BigNumber}
+ */
+var toTwosComplement = function (number) {
+ var bigNumber = toBigNumber(number);
+ if (bigNumber.lessThan(0)) {
+ return new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(bigNumber).plus(1);
+ }
+ return bigNumber;
+};
+
+/**
+ * Checks if the given string has proper length
+ *
+ * @method isAddress
+ * @param {String} address the given HEX adress
+ * @return {Boolean}
+*/
+var isAddress = function(address) {
+ if (!isString(address)) {
+ return false;
+ }
+
+ return ((address.indexOf('0x') === 0 && address.length === 42) ||
+ (address.indexOf('0x') === -1 && address.length === 40));
+};
+
+/**
+ * Returns true if object is BigNumber, otherwise false
+ *
+ * @method isBigNumber
+ * @param {Object}
+ * @return {Boolean}
+ */
+var isBigNumber = function (object) {
+ return object instanceof BigNumber ||
+ (object && object.constructor && object.constructor.name === 'BigNumber');
+};
+
+/**
+ * Returns true if object is string, otherwise false
+ *
+ * @method isString
+ * @param {Object}
+ * @return {Boolean}
+ */
+var isString = function (object) {
+ return typeof object === 'string' ||
+ (object && object.constructor && object.constructor.name === 'String');
+};
+
+/**
+ * Returns true if object is function, otherwise false
+ *
+ * @method isFunction
+ * @param {Object}
+ * @return {Boolean}
+ */
+var isFunction = function (object) {
+ return typeof object === 'function';
};
+module.exports = {
+ findIndex: findIndex,
+ toHex: toHex,
+ toDecimal: toDecimal,
+ fromDecimal: fromDecimal,
+ toAscii: toAscii,
+ fromAscii: fromAscii,
+ extractDisplayName: extractDisplayName,
+ extractTypeName: extractTypeName,
+ filterFunctions: filterFunctions,
+ filterEvents: filterEvents,
+ toWei: toWei,
+ fromWei: fromWei,
+ toBigNumber: toBigNumber,
+ toTwosComplement: toTwosComplement,
+ isBigNumber: isBigNumber,
+ isAddress: isAddress,
+ isFunction: isFunction,
+ isString: isString
+};
-},{}],3:[function(require,module,exports){
+
+},{}],6:[function(require,module,exports){
+/*
+ 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 web3.js
+ * @authors:
+ * Jeffrey Wilcke <jeff@ethdev.com>
+ * Marek Kotewicz <marek@ethdev.com>
+ * Marian Oancea <marian@ethdev.com>
+ * Gav Wood <g@ethdev.com>
+ * @date 2014
+ */
+
+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 utils = require('./utils/utils');
+var formatters = require('./solidity/formatters');
+var requestManager = require('./web3/requestmanager');
+var c = require('./utils/config');
+
+/// @returns an array of objects describing web3 api methods
+var web3Methods = function () {
+ return [
+ { name: 'sha3', call: 'web3_sha3' }
+ ];
+};
+
+/// 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;
+ }
+
+ });
+};
+
+/// creates properties in a given object based on properties description on input
+/// setups api calls for these properties
+var setupProperties = function (obj, properties) {
+ properties.forEach(function (property) {
+ var 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;
+ Object.defineProperty(obj, property.name, proto);
+
+ });
+};
+
+/*jshint maxparams:4 */
+var startPolling = function (method, id, callback, uninstall) {
+ web3.manager.startPolling({
+ method: method,
+ params: [id]
+ }, id, callback, uninstall);
+};
+/*jshint maxparams:3 */
+
+var stopPolling = function (id) {
+ web3.manager.stopPolling(id);
+};
+
+var ethWatch = {
+ startPolling: startPolling.bind(null, 'eth_getFilterChanges'),
+ stopPolling: stopPolling
+};
+
+var shhWatch = {
+ startPolling: startPolling.bind(null, 'shh_getFilterChanges'),
+ stopPolling: stopPolling
+};
+
+/// setups web3 object, and it's in-browser executed methods
+var web3 = {
+ 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);
+ }
+ }
+};
+
+
+// ADD defaultblock
+Object.defineProperty(web3.eth, 'defaultBlock', {
+ get: function () {
+ return c.ETH_DEFAULTBLOCK;
+ },
+ set: function (val) {
+ c.ETH_DEFAULTBLOCK = val;
+ return c.ETH_DEFAULTBLOCK;
+ }
+});
+
+
+/// setups all api methods
+setupMethods(web3, web3Methods());
+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());
+
+module.exports = web3;
+
+
+},{"./solidity/formatters":2,"./utils/config":4,"./utils/utils":5,"./web3/db":8,"./web3/eth":9,"./web3/filter":11,"./web3/net":15,"./web3/requestmanager":17,"./web3/shh":18,"./web3/watches":20}],7:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -283,9 +1339,9 @@ module.exports = {
* @date 2014
*/
-var web3 = require('./web3');
-var abi = require('./abi');
-var utils = require('./utils');
+var web3 = require('../web3');
+var abi = require('../solidity/abi');
+var utils = require('../utils/utils');
var eventImpl = require('./event');
var signature = require('./signature');
@@ -505,7 +1561,7 @@ function Contract(abi, address) {
module.exports = contract;
-},{"./abi":1,"./event":6,"./signature":14,"./utils":16,"./web3":18}],4:[function(require,module,exports){
+},{"../solidity/abi":1,"../utils/utils":5,"../web3":6,"./event":10,"./signature":19}],8:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -542,7 +1598,7 @@ module.exports = {
methods: methods
};
-},{}],5:[function(require,module,exports){
+},{}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -565,81 +1621,124 @@ module.exports = {
* @date 2015
*/
+/**
+ * Web3
+ *
+ * @module web3
+ */
+
+/**
+ * Eth methods and properties
+ *
+ * An example method object can look as follows:
+ *
+ * {
+ * name: 'getBlock',
+ * call: blockCall,
+ * 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
+ * ]
+ * },
+ *
+ * @class [web3] eth
+ * @constructor
+ */
+
+
var formatters = require('./formatters');
+var utils = require('../utils/utils');
var blockCall = function (args) {
- return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber";
};
-var transactionCall = function (args) {
- return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
+var transactionFromBlockCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';
};
var uncleCall = function (args) {
- return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';
};
-var transactionCountCall = function (args) {
- return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber';
+var getBlockTransactionCountCall = function (args) {
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';
};
var uncleCountCall = function (args) {
- return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber';
+ return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';
};
/// @returns an array of objects describing web3.eth api methods
var methods = [
- { name: 'getBalance', call: 'eth_balanceAt', outputFormatter: formatters.convertToBigNumber},
- { name: 'getState', call: 'eth_stateAt' },
- { name: 'getStorage', call: 'eth_storageAt' },
- { name: 'getData', call: 'eth_codeAt' },
- { name: 'getBlock', call: blockCall, outputFormatter: formatters.outputBlockFormatter},
- { name: 'getUncle', call: uncleCall, outputFormatter: formatters.outputBlockFormatter},
- { name: 'getCompilers', call: 'eth_compilers' },
- { name: 'getBlockTransactionCount', call: transactionCountCall },
- { name: 'getBlockUncleCount', call: uncleCountCall },
- { name: 'getTransaction', call: transactionCall, outputFormatter: formatters.outputTransactionFormatter },
- { name: 'getTransactionCount', call: 'eth_countAt'},
- { name: 'sendTransaction', call: 'eth_transact', inputFormatter: formatters.inputTransactionFormatter },
- { name: 'call', call: 'eth_call' },
- { name: 'compile.solidity', call: 'eth_solidity' },
- { name: 'compile.lll', call: 'eth_lll' },
- { name: 'compile.serpent', call: 'eth_serpent' },
+ { 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', inputFormatter: utils.toHex },
+ { 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: 'getBalance' },
- { name: 'stateAt', call: 'eth_stateAt', newMethod: 'getState' },
- { name: 'storageAt', call: 'eth_storageAt', newMethod: 'getStorage' },
- { name: 'countAt', call: 'eth_countAt', newMethod: 'getTransactionCount' },
- { name: 'codeAt', call: 'eth_codeAt', newMethod: 'getData' },
- { name: 'transact', call: 'eth_transact', newMethod: 'sendTransaction' },
- { name: 'block', call: blockCall, newMethod: 'getBlock' },
- { name: 'transaction', call: transactionCall, newMethod: 'getTransaction' },
- { name: 'uncle', call: uncleCall, newMethod: 'getUncle' },
- { name: 'compilers', call: 'eth_compilers', newMethod: 'getCompilers' },
- { name: 'solidity', call: 'eth_solidity', newMethod: 'compile.solidity' },
- { name: 'lll', call: 'eth_lll', newMethod: 'compile.lll' },
- { name: 'serpent', call: 'eth_serpent', newMethod: 'compile.serpent' },
- { name: 'transactionCount', call: transactionCountCall, newMethod: 'getBlockTransactionCount' },
- { name: 'uncleCount', call: uncleCountCall, newMethod: 'getBlockUncleCount' },
+ { 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' }
];
/// @returns an array of objects describing web3.eth api properties
var properties = [
- { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
- { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
- { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
+ { name: 'coinbase', getter: 'eth_coinbase'},
+ { name: 'mining', getter: 'eth_mining'},
{ name: 'gasPrice', getter: 'eth_gasPrice', outputFormatter: formatters.convertToBigNumber},
{ name: 'accounts', getter: 'eth_accounts' },
- { name: 'peerCount', getter: 'eth_peerCount' },
- { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
- { name: 'blockNumber', getter: 'eth_number'},
+ { name: 'blockNumber', getter: 'eth_blockNumber', outputFormatter: utils.toDecimal},
// deprecated properties
- { name: 'number', getter: 'eth_number', newProperty: 'blockNumber'}
+ { 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'}
];
@@ -649,7 +1748,7 @@ module.exports = {
};
-},{"./formatters":8}],6:[function(require,module,exports){
+},{"../utils/utils":5,"./formatters":12}],10:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -672,8 +1771,8 @@ module.exports = {
* @date 2014
*/
-var abi = require('./abi');
-var utils = require('./utils');
+var abi = require('../solidity/abi');
+var utils = require('../utils/utils');
var signature = require('./signature');
/// filter inputs array && returns only indexed (or not) inputs
@@ -789,7 +1888,7 @@ module.exports = {
};
-},{"./abi":1,"./signature":14,"./utils":16}],7:[function(require,module,exports){
+},{"../solidity/abi":1,"../utils/utils":5,"./signature":19}],11:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -815,6 +1914,8 @@ module.exports = {
* @date 2014
*/
+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) {
@@ -830,25 +1931,56 @@ var implementationIsValid = function (i) {
/// @param should be string or object
/// @returns options string or object
var getOptions = function (options) {
+ /*jshint maxcomplexity:5 */
+
if (typeof options === 'string') {
return options;
}
options = options || {};
- if (options.topics) {
- console.warn('"topics" is deprecated, is "topic" instead');
+ 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);
+ });
+ }
+
+
// evaluate lazy properties
return {
+ fromBlock: utils.toHex(options.fromBlock),
+ toBlock: utils.toHex(options.toBlock),
+ limit: utils.toHex(options.limit),
+ offset: utils.toHex(options.offset),
to: options.to,
- topic: options.topic,
- earliest: options.earliest,
- latest: options.latest,
- max: options.max,
- skip: options.skip,
- address: options.address
+ address: options.address,
+ topics: options.topics
};
};
@@ -866,6 +1998,8 @@ var filter = function(options, implementation, formatter) {
options = getOptions(options);
var callbacks = [];
var filterId = implementation.newFilter(options);
+
+ // call the callbacks
var onMessages = function (messages) {
messages.forEach(function (message) {
message = formatter ? formatter(message) : message;
@@ -927,7 +2061,7 @@ var filter = function(options, implementation, formatter) {
module.exports = filter;
-},{}],8:[function(require,module,exports){
+},{"../utils/utils":5}],12:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -947,286 +2081,188 @@ module.exports = filter;
/** @file formatters.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
+ * Fabian Vogelsteller <fabian@ethdev.com>
* @date 2015
*/
-if ("build" !== 'build') {/*
- var BigNumber = require('bignumber.js'); // jshint ignore:line
-*/}
-
-var utils = require('./utils');
-var c = require('./const');
-
-/// @param string string to be padded
-/// @param number of characters that result string should have
-/// @param sign, by default 0
-/// @returns right aligned string
-var padLeft = function (string, chars, sign) {
- return new Array(chars - string.length + 1).join(sign ? sign : "0") + string;
-};
+var utils = require('../utils/utils');
-/// Formats input value to byte representation of int
-/// If value is negative, return it's two's complement
-/// If the value is floating point, round it down
-/// @returns right-aligned byte representation of int
-var formatInputInt = function (value) {
- /*jshint maxcomplexity:7 */
- var padding = c.ETH_PADDING * 2;
- if (utils.isBigNumber(value) || typeof value === 'number') {
- if (typeof value === 'number')
- value = new BigNumber(value);
- BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
- value = value.round();
-
- if (value.lessThan(0))
- value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
- value = value.toString(16);
- }
- else if (typeof value === 'string') {
- if (value.indexOf('0x') === 0) {
- value = value.substr(2);
- } else {
- value = formatInputInt(new BigNumber(value));
- }
- }
- else
- value = (+value).toString(16);
- return padLeft(value, padding);
-};
-
-/// Formats input value to byte representation of string
-/// @returns left-algined byte representation of string
-var formatInputString = function (value) {
- return utils.fromAscii(value, c.ETH_PADDING).substr(2);
-};
-
-/// Formats input value to byte representation of bool
-/// @returns right-aligned byte representation bool
-var formatInputBool = function (value) {
- return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
-};
-
-/// Formats input value to byte representation of real
-/// Values are multiplied by 2^m and encoded as integers
-/// @returns byte representation of real
-var formatInputReal = function (value) {
- return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
-};
-
-
-/// Check if input value is negative
-/// @param value is hex format
-/// @returns true if it is negative, otherwise false
-var signedIsNegative = function (value) {
- return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';
+/**
+ * Should the input to a big number
+ *
+ * @method convertToBigNumber
+ * @param {String|Number|BigNumber}
+ * @returns {BigNumber} object
+ */
+var convertToBigNumber = function (value) {
+ return utils.toBigNumber(value);
};
-/// Formats input right-aligned input bytes to int
-/// @returns right-aligned input bytes formatted to int
-var formatOutputInt = function (value) {
-
- value = value || "0";
+/**
+ * Formats the input of a transaction and converts all values to HEX
+ *
+ * @method inputTransactionFormatter
+ * @param {Object} transaction options
+ * @returns object
+*/
+var inputTransactionFormatter = function (options){
- // check if it's negative number
- // it it is, return two's complement
- if (signedIsNegative(value)) {
- return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
+ // make code -> data
+ if (options.code) {
+ options.data = options.code;
+ delete options.code;
}
- return new BigNumber(value, 16);
-};
-
-
-/// Formats big right-aligned input bytes to uint
-/// @returns right-aligned input bytes formatted to uint
-var formatOutputUInt = function (value) {
- value = value || "0";
- return new BigNumber(value, 16);
-};
-
-/// @returns input bytes formatted to real
-var formatOutputReal = function (value) {
- return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128));
-};
-
-/// @returns input bytes formatted to ureal
-var formatOutputUReal = function (value) {
- return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128));
-};
-
-/// @returns right-aligned input bytes formatted to hex
-var formatOutputHash = function (value) {
- return "0x" + value;
-};
-
-/// @returns right-aligned input bytes formatted to bool
-var formatOutputBool = function (value) {
- return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
-};
-/// @returns left-aligned input bytes formatted to ascii string
-var formatOutputString = function (value) {
- return utils.toAscii(value);
-};
+ ['gasPrice', 'gas', 'value'].forEach(function(key){
+ options[key] = utils.fromDecimal(options[key]);
+ });
-/// @returns right-aligned input bytes formatted to address
-var formatOutputAddress = function (value) {
- return "0x" + value.slice(value.length - 40, value.length);
+ return options;
};
-
-/// Formats the input to a big number
-/// @returns a BigNumber object
-var convertToBigNumber = function (value) {
-
- // remove the leading 0x
- if(typeof value === 'string')
- value = value.replace('0x', '');
-
- value = value || "0";
-
- return new BigNumber(value, 16);
+/**
+ * Formats the output of a transaction to its proper values
+ *
+ * @method outputTransactionFormatter
+ * @param {Object} transaction
+ * @returns {Object} transaction
+*/
+var outputTransactionFormatter = function (tx){
+ 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 transaction and converts all values to HEX
-
-@returns object
+ * Formats the input of a call and converts all values to HEX
+ *
+ * @method inputCallFormatter
+ * @param {Object} transaction options
+ * @returns object
*/
-var inputTransactionFormatter = function(options){
+var inputCallFormatter = function (options){
// make code -> data
- if(options.code) {
+ if (options.code) {
options.data = options.code;
delete options.code;
}
- // make endowment -> value
- if(options.endowment) {
- options.value = options.endowment;
- delete options.endowment;
- }
-
-
- // format the following options
- /*jshint maxcomplexity:5 */
- ['gasPrice', 'value'].forEach(function(key){
-
- // if hex or string integer
- if(typeof options[key] === 'string') {
-
- // if not hex assume its a number string
- if(options[key].indexOf('0x') === -1)
- options[key] = utils.fromDecimal(options[key]);
-
- // if number
- } else if(typeof options[key] === 'number') {
- options[key] = utils.fromDecimal(options[key]);
-
- // if bignumber
- } else if(options[key] instanceof BigNumber) {
- options[key] = '0x'+ options[key].toString(16);
- }
- });
-
- // format gas to number
- options.gas = Number(options.gas);
-
-
return options;
};
-/**
-Formats the output of a transaction to its proper values
-@returns object
+/**
+ * Formats the output of a block to its proper values
+ *
+ * @method outputBlockFormatter
+ * @param {Object} block object
+ * @returns {Object} block object
*/
-var outputTransactionFormatter = function(tx){
- // transform to number
- tx.gas = Number(tx.gas);
+var outputBlockFormatter = function(block){
- // gasPrice to bignumber
- if(typeof tx.gasPrice === 'string' && tx.gasPrice.indexOf('0x') === 0)
- tx.gasPrice = new BigNumber(tx.gasPrice, 16);
- else
- tx.gasPrice = new BigNumber(tx.gasPrice.toString(10), 10);
+ // transform to number
+ block.gasLimit = utils.toDecimal(block.gasLimit);
+ block.gasUsed = utils.toDecimal(block.gasUsed);
+ block.size = utils.toDecimal(block.size);
+ block.timestamp = utils.toDecimal(block.timestamp);
+ block.number = utils.toDecimal(block.number);
+
+ block.minGasPrice = utils.toBigNumber(block.minGasPrice);
+ block.difficulty = utils.toBigNumber(block.difficulty);
+ block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);
+
+ if(block.transactions instanceof Array) {
+ block.transactions.forEach(function(item){
+ if(!utils.isString(item))
+ return outputTransactionFormatter(item);
+ });
+ }
- // value to bignumber
- if(typeof tx.value === 'string' && tx.value.indexOf('0x') === 0)
- tx.value = new BigNumber(tx.value, 16);
- else
- tx.value = new BigNumber(tx.value.toString(10), 10);
+ return block;
+};
- return tx;
+/**
+ * Formats the output of a log
+ *
+ * @method outputLogFormatter
+ * @param {Object} log object
+ * @returns {Object} log
+*/
+var outputLogFormatter = function(log){
+ log.number = utils.toDecimal(log.number);
+ return log;
};
/**
-Formats the output of a block to its proper values
-
-@returns object
+ * Formats the input of a whisper post and converts all values to HEX
+ *
+ * @method inputPostFormatter
+ * @param {Object} transaction object
+ * @returns {Object}
*/
-var outputBlockFormatter = function(block){
- /*jshint maxcomplexity:7 */
+var inputPostFormatter = function(post){
- // transform to number
- block.gasLimit = Number(block.gasLimit);
- block.gasUsed = Number(block.gasUsed);
- block.size = Number(block.size);
- block.timestamp = Number(block.timestamp);
- block.number = Number(block.number);
-
- // minGasPrice to bignumber
- if(block.minGasPrice) {
- if(typeof block.minGasPrice === 'string' && block.minGasPrice.indexOf('0x') === 0)
- block.minGasPrice = new BigNumber(block.minGasPrice, 16);
- else
- block.minGasPrice = new BigNumber(block.minGasPrice.toString(10), 10);
- }
+ post.payload = utils.toHex(post.payload);
+ post.ttl = utils.fromDecimal(post.ttl);
+ post.workToProve = utils.fromDecimal(post.workToProve);
+ if(!(post.topic instanceof Array))
+ post.topic = [post.topic];
- // difficulty to bignumber
- if(block.difficulty) {
- if(typeof block.difficulty === 'string' && block.difficulty.indexOf('0x') === 0)
- block.difficulty = new BigNumber(block.difficulty, 16);
- else
- block.difficulty = new BigNumber(block.difficulty.toString(10), 10);
- }
+ // format the following options
+ post.topic = post.topic.map(function(topic){
+ return utils.fromAscii(topic);
+ });
- // difficulty to bignumber
- if(block.totalDifficulty) {
- if(typeof block.totalDifficulty === 'string' && block.totalDifficulty.indexOf('0x') === 0)
- block.totalDifficulty = new BigNumber(block.totalDifficulty, 16);
- else
- block.totalDifficulty = new BigNumber(block.totalDifficulty.toString(10), 10);
+ return post;
+};
+
+/**
+ * Formats the output of a received post message
+ *
+ * @method outputPostFormatter
+ * @param {Object}
+ * @returns {Object}
+ */
+var outputPostFormatter = function(post){
+
+ post.expiry = utils.toDecimal(post.expiry);
+ post.sent = utils.toDecimal(post.sent);
+ post.ttl = utils.toDecimal(post.ttl);
+ 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) { }
}
- return block;
-};
+ // format the following options
+ post.topic = post.topic.map(function(topic){
+ return utils.toAscii(topic);
+ });
+ return post;
+};
module.exports = {
- formatInputInt: formatInputInt,
- formatInputString: formatInputString,
- formatInputBool: formatInputBool,
- formatInputReal: formatInputReal,
- formatOutputInt: formatOutputInt,
- formatOutputUInt: formatOutputUInt,
- formatOutputReal: formatOutputReal,
- formatOutputUReal: formatOutputUReal,
- formatOutputHash: formatOutputHash,
- formatOutputBool: formatOutputBool,
- formatOutputString: formatOutputString,
- formatOutputAddress: formatOutputAddress,
convertToBigNumber: convertToBigNumber,
inputTransactionFormatter: inputTransactionFormatter,
outputTransactionFormatter: outputTransactionFormatter,
- outputBlockFormatter: outputBlockFormatter
+ inputCallFormatter: inputCallFormatter,
+ outputBlockFormatter: outputBlockFormatter,
+ outputLogFormatter: outputLogFormatter,
+ inputPostFormatter: inputPostFormatter,
+ outputPostFormatter: outputPostFormatter
};
-},{"./const":2,"./utils":16}],9:[function(require,module,exports){
+},{"../utils/utils":5}],13:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1243,7 +2279,7 @@ module.exports = {
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 httpsync.js
+/** @file httpprovider.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* Marian Oancea <marian@ethdev.com>
@@ -1254,29 +2290,50 @@ if ("build" !== 'build') {/*
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
*/}
-var HttpSyncProvider = function (host) {
+var HttpProvider = function (host) {
+ this.name = 'HTTP';
this.handlers = [];
this.host = host || 'http://localhost:8080';
};
-HttpSyncProvider.prototype.send = function (payload) {
- //var data = formatJsonRpcObject(payload);
-
+HttpProvider.prototype.send = function (payload, callback) {
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
- request.send(JSON.stringify(payload));
- var result = request.responseText;
- // check request.status
- if(request.status !== 200)
- return;
- return JSON.parse(result);
+ // 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));
+
+ // check request.status
+ if(request.status !== 200)
+ return;
+ return JSON.parse(request.responseText);
+
+ }
};
-module.exports = HttpSyncProvider;
+module.exports = HttpProvider;
-},{}],10:[function(require,module,exports){
+},{}],14:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1343,7 +2400,50 @@ module.exports = {
-},{}],11:[function(require,module,exports){
+},{}],15:[function(require,module,exports){
+/*
+ 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 eth.js
+ * @authors:
+ * Marek Kotewicz <marek@ethdev.com>
+ * @date 2015
+ */
+
+var utils = require('../utils/utils');
+
+/// @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 },
+];
+
+
+module.exports = {
+ methods: methods,
+ properties: properties
+};
+
+
+},{"../utils/utils":5}],16:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1378,7 +2478,7 @@ QtSyncProvider.prototype.send = function (payload) {
module.exports = QtSyncProvider;
-},{}],12:[function(require,module,exports){
+},{}],17:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1405,7 +2505,7 @@ module.exports = QtSyncProvider;
*/
var jsonrpc = require('./jsonrpc');
-var c = require('./const');
+var c = require('../utils/config');
/**
* It's responsible for passing messages to providers
@@ -1417,16 +2517,29 @@ var requestManager = function() {
var timeout = null;
var provider;
- var send = function (data) {
- /*jshint maxcomplexity: 6 */
+ var send = function (data, callback) {
+ /*jshint maxcomplexity: 7 */
- // format the input before sending
+ // FORMAT BASED ON ONE FORMATTER function
if(typeof data.inputFormatter === 'function') {
- data.params = Array.prototype.map.call(data.params, function(item){
- return data.inputFormatter(item);
+ 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 payload = jsonrpc.toPayload(data.method, data.params);
if (!provider) {
@@ -1434,17 +2547,43 @@ var requestManager = function() {
return null;
}
- var result = 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);
+ });
- if (!jsonrpc.isValidResponse(result)) {
- console.log(result);
- if(typeof result === 'object' && result.error && result.error.message)
- console.error(result.error.message);
- return null;
+ // SYNC
+ } else {
+ var result = provider.send(payload);
+
+ if (!jsonrpc.isValidResponse(result)) {
+ console.log(result);
+ if(typeof result === 'object' && result.error && result.error.message)
+ console.error(result.error.message);
+ return null;
+ }
+
+ // format the output
+ return (typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result;
}
- // format the output
- return (typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result;
};
var setProvider = function (p) {
@@ -1481,11 +2620,13 @@ var requestManager = function() {
var poll = function () {
polls.forEach(function (data) {
- var result = send(data.data);
- if (!(result instanceof Array) || result.length === 0) {
- return;
- }
- data.callback(result);
+ // send async
+ send(data.data, function(result){
+ if (!(result instanceof Array) || result.length === 0) {
+ return;
+ }
+ data.callback(result);
+ });
});
timeout = setTimeout(poll, c.ETH_POLLING_TIMEOUT);
};
@@ -1504,7 +2645,7 @@ var requestManager = function() {
module.exports = requestManager;
-},{"./const":2,"./jsonrpc":10}],13:[function(require,module,exports){
+},{"../utils/config":4,"./jsonrpc":14}],18:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1527,17 +2668,19 @@ module.exports = requestManager;
* @date 2015
*/
+var formatters = require('./formatters');
+
/// @returns an array of objects describing web3.shh api methods
var methods = function () {
return [
- { name: 'post', call: 'shh_post' },
+ { name: 'post', call: 'shh_post', inputFormatter: formatters.inputPostFormatter },
{ name: 'newIdentity', call: 'shh_newIdentity' },
- { name: 'hasIdentity', call: 'shh_haveIdentity' },
+ { name: 'hasIdentity', call: 'shh_hasIdentity' },
{ name: 'newGroup', call: 'shh_newGroup' },
{ name: 'addToGroup', call: 'shh_addToGroup' },
// deprecated
- { name: 'haveIdentity', call: 'shh_haveIdentity', newMethod: 'hasIdentity' },
+ { name: 'haveIdentity', call: 'shh_haveIdentity', newMethod: 'shh.hasIdentity' },
];
};
@@ -1546,7 +2689,7 @@ module.exports = {
};
-},{}],14:[function(require,module,exports){
+},{"./formatters":12}],19:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -1569,8 +2712,8 @@ module.exports = {
* @date 2015
*/
-var web3 = require('./web3');
-var c = require('./const');
+var web3 = require('../web3');
+var c = require('../utils/config');
/// @param function name for which we want to get signature
/// @returns signature of function with given name
@@ -1590,402 +2733,7 @@ module.exports = {
};
-},{"./const":2,"./web3":18}],15:[function(require,module,exports){
-/*
- 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 types.js
- * @authors:
- * Marek Kotewicz <marek@ethdev.com>
- * @date 2015
- */
-
-var f = require('./formatters');
-
-/// @param expected type prefix (string)
-/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
-var prefixedType = function (prefix) {
- return function (type) {
- return type.indexOf(prefix) === 0;
- };
-};
-
-/// @param expected type name (string)
-/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
-var namedType = function (name) {
- return function (type) {
- return name === type;
- };
-};
-
-/// Setups input formatters for solidity types
-/// @returns an array of input formatters
-var inputTypes = function () {
-
- return [
- { type: prefixedType('uint'), format: f.formatInputInt },
- { type: prefixedType('int'), format: f.formatInputInt },
- { type: prefixedType('hash'), format: f.formatInputInt },
- { type: prefixedType('string'), format: f.formatInputString },
- { type: prefixedType('real'), format: f.formatInputReal },
- { type: prefixedType('ureal'), format: f.formatInputReal },
- { type: namedType('address'), format: f.formatInputInt },
- { type: namedType('bool'), format: f.formatInputBool }
- ];
-};
-
-/// Setups output formaters for solidity types
-/// @returns an array of output formatters
-var outputTypes = function () {
-
- return [
- { type: prefixedType('uint'), format: f.formatOutputUInt },
- { type: prefixedType('int'), format: f.formatOutputInt },
- { type: prefixedType('hash'), format: f.formatOutputHash },
- { type: prefixedType('string'), format: f.formatOutputString },
- { type: prefixedType('real'), format: f.formatOutputReal },
- { type: prefixedType('ureal'), format: f.formatOutputUReal },
- { type: namedType('address'), format: f.formatOutputAddress },
- { type: namedType('bool'), format: f.formatOutputBool }
- ];
-};
-
-module.exports = {
- prefixedType: prefixedType,
- namedType: namedType,
- inputTypes: inputTypes,
- outputTypes: outputTypes
-};
-
-
-},{"./formatters":8}],16:[function(require,module,exports){
-/*
- 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 utils.js
- * @authors:
- * Marek Kotewicz <marek@ethdev.com>
- * @date 2015
- */
-
-var c = require('./const');
-
-if ("build" !== 'build') {/*
- var BigNumber = require('bignumber.js'); // jshint ignore:line
-*/}
-
-var unitMap = {
- 'wei': '1',
- 'kwei': '1000',
- 'ada': '1000',
- 'mwei': '1000000',
- 'babbage': '1000000',
- 'gwei': '1000000000',
- 'shannon': '1000000000',
- 'szabo': '1000000000000',
- 'finney': '1000000000000000',
- 'ether': '1000000000000000000',
- 'kether': '1000000000000000000000',
- 'grand': '1000000000000000000000',
- 'einstein': '1000000000000000000000',
- 'mether': '1000000000000000000000000',
- 'gether': '1000000000000000000000000000',
- 'tether': '1000000000000000000000000000000'
-};
-
-
-/// Finds first index of array element matching pattern
-/// @param array
-/// @param callback pattern
-/// @returns index of element
-var findIndex = function (array, callback) {
- var end = false;
- var i = 0;
- for (; i < array.length && !end; i++) {
- end = callback(array[i]);
- }
- return end ? i - 1 : -1;
-};
-
-/// @returns ascii string representation of hex value prefixed with 0x
-var toAscii = function(hex) {
-// Find termination
- var str = "";
- var i = 0, l = hex.length;
- if (hex.substring(0, 2) === '0x') {
- i = 2;
- }
- for (; i < l; i+=2) {
- var code = parseInt(hex.substr(i, 2), 16);
- if (code === 0) {
- break;
- }
-
- str += String.fromCharCode(code);
- }
-
- return str;
-};
-
-var toHex = function(str) {
- var hex = "";
- for(var i = 0; i < str.length; i++) {
- var n = str.charCodeAt(i).toString(16);
- hex += n.length < 2 ? '0' + n : n;
- }
-
- return hex;
-};
-
-/// @returns hex representation (prefixed by 0x) of ascii string
-var fromAscii = function(str, pad) {
- pad = pad === undefined ? 0 : pad;
- var hex = toHex(str);
- while (hex.length < pad*2)
- hex += "00";
- return "0x" + hex;
-};
-
-/// @returns display name for function/event eg. multiply(uint256) -> multiply
-var extractDisplayName = function (name) {
- var length = name.indexOf('(');
- return length !== -1 ? name.substr(0, length) : name;
-};
-
-/// @returns overloaded part of function/event name
-var extractTypeName = function (name) {
- /// TODO: make it invulnerable
- var length = name.indexOf('(');
- return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
-};
-
-/// Filters all function from input abi
-/// @returns abi array with filtered objects of type 'function'
-var filterFunctions = function (json) {
- return json.filter(function (current) {
- return current.type === 'function';
- });
-};
-
-/// Filters all events form input abi
-/// @returns abi array with filtered objects of type 'event'
-var filterEvents = function (json) {
- return json.filter(function (current) {
- return current.type === 'event';
- });
-};
-
-/// used to transform value/string to eth string
-/// TODO: use BigNumber.js to parse int
-/// TODO: add tests for it!
-var toEth = function (str) {
-
- console.warn('This method is deprecated please use eth.fromWei(BigNumberOrNumber, unit) instead.');
-
- /*jshint maxcomplexity:7 */
- var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str.replace(/,/g,'').replace(/ /g,'')) : str;
- var unit = 0;
- var units = c.ETH_UNITS;
- while (val > 3000 && unit < units.length - 1)
- {
- val /= 1000;
- unit++;
- }
- var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
- var replaceFunction = function($0, $1, $2) {
- return $1 + ',' + $2;
- };
-
- while (true) {
- var o = s;
- s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
- if (o === s)
- break;
- }
- return s + ' ' + units[unit];
-};
-
-
-var toDecimal = function (val) {
- // remove 0x and place 0, if it's required
- val = val.length > 2 ? val.substring(2) : "0";
- return (new BigNumber(val, 16).toString(10));
-};
-
-var fromDecimal = function (val) {
- return "0x" + (new BigNumber(val).toString(16));
-};
-
-
-/**
-Takes a number of wei and converts it to any other ether unit.
-
-Possible units are:
-
- - kwei/ada
- - mwei/babbage
- - gwei/shannon
- - szabo
- - finney
- - ether
- - kether/grand/einstein
- - mether
- - gether
- - tether
-
-@method fromWei
-@param {Number|String} number can be a number, number string or a HEX of a decimal
-@param {String} unit the unit to convert to
-@return {String|Object} When given a BigNumber object it returns one as well, otherwise a number
-*/
-var fromWei = function(number, unit) {
- /*jshint maxcomplexity: 6 */
- unit = unit.toLowerCase();
-
- var isBigNumber = true;
-
- if(!unitMap[unit]) {
- console.warn('This unit doesn\'t exists, please use the one of the following units' , unitMap);
- return number;
- }
-
- if(!number)
- return number;
-
- if(typeof number === 'string' && number.indexOf('0x') === 0) {
- isBigNumber = false;
- number = new BigNumber(number, 16);
- }
-
- if(!(number instanceof BigNumber)) {
- isBigNumber = false;
- number = new BigNumber(number.toString(10), 10); // toString to prevent errors, the user have to handle giving correct bignums themselves
- }
-
- number = number.dividedBy(new BigNumber(unitMap[unit], 10));
-
- return (isBigNumber) ? number : number.toString(10);
-};
-
-/**
-Takes a number of a unit and converts it to wei.
-
-Possible units are:
-
- - kwei/ada
- - mwei/babbage
- - gwei/shannon
- - szabo
- - finney
- - ether
- - kether/grand/einstein
- - mether
- - gether
- - tether
-
-@method toWei
-@param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal
-@param {String} unit the unit to convert to
-@return {String|Object} When given a BigNumber object it returns one as well, otherwise a number
-*/
-var toWei = function(number, unit) {
- /*jshint maxcomplexity: 6 */
- unit = unit.toLowerCase();
-
- var isBigNumber = true;
-
- if(!unitMap[unit]) {
- console.warn('This unit doesn\'t exists, please use the one of the following units' , unitMap);
- return number;
- }
-
- if(!number)
- return number;
-
- if(typeof number === 'string' && number.indexOf('0x') === 0) {
- isBigNumber = false;
- number = new BigNumber(number, 16);
- }
-
- if(!(number instanceof BigNumber)) {
- isBigNumber = false;
- number = new BigNumber(number.toString(10), 10);// toString to prevent errors, the user have to handle giving correct bignums themselves
- }
-
-
- number = number.times(new BigNumber(unitMap[unit], 10));
-
- return (isBigNumber) ? number : number.toString(10);
-};
-
-
-/**
-Checks if the given string is a valid ethereum HEX address.
-
-@method isAddress
-@param {String} address the given HEX adress
-@return {Boolean}
-*/
-var isAddress = function(address) {
- if(address.indexOf('0x') === 0 && address.length !== 42)
- return false;
- if(address.indexOf('0x') === -1 && address.length !== 40)
- return false;
-
- return /^\w+$/.test(address);
-};
-
-var isBigNumber = function (value) {
- return value instanceof BigNumber ||
- (value && value.constructor && value.constructor.name === 'BigNumber');
-};
-
-
-module.exports = {
- findIndex: findIndex,
- toDecimal: toDecimal,
- fromDecimal: fromDecimal,
- toAscii: toAscii,
- fromAscii: fromAscii,
- extractDisplayName: extractDisplayName,
- extractTypeName: extractTypeName,
- filterFunctions: filterFunctions,
- filterEvents: filterEvents,
- toEth: toEth,
- toWei: toWei,
- fromWei: fromWei,
- isAddress: isAddress,
- isBigNumber: isBigNumber
-};
-
-
-},{"./const":2}],17:[function(require,module,exports){
+},{"../utils/config":4,"../web3":6}],20:[function(require,module,exports){
/*
This file is part of ethereum.js.
@@ -2011,13 +2759,13 @@ module.exports = {
/// @returns an array of objects describing web3.eth.filter api methods
var eth = function () {
var newFilter = function (args) {
- return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
+ return typeof args[0] === 'string' ? 'eth_newBlockFilter' : 'eth_newFilter';
};
return [
{ name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'eth_uninstallFilter' },
- { name: 'getLogs', call: 'eth_filterLogs' }
+ { name: 'getLogs', call: 'eth_getFilterLogs' }
];
};
@@ -2036,259 +2784,16 @@ module.exports = {
};
-},{}],18:[function(require,module,exports){
-/*
- 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 web3.js
- * @authors:
- * Jeffrey Wilcke <jeff@ethdev.com>
- * Marek Kotewicz <marek@ethdev.com>
- * Marian Oancea <marian@ethdev.com>
- * Gav Wood <g@ethdev.com>
- * @date 2014
- */
-
-// if (process.env.NODE_ENV !== 'build') {
-// var BigNumber = require('bignumber.js');
-// }
-
-var eth = require('./eth');
-var db = require('./db');
-var shh = require('./shh');
-var watches = require('./watches');
-var filter = require('./filter');
-var utils = require('./utils');
-var requestManager = require('./requestmanager');
-
-/// @returns an array of objects describing web3 api methods
-var web3Methods = function () {
- return [
- { name: 'sha3', call: 'web3_sha3' }
- ];
-};
-
-/// 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 () {
- var args = Array.prototype.slice.call(arguments);
- var call = typeof method.call === 'function' ? method.call(args) : method.call;
-
- // show deprecated warning
- if(method.newMethod)
- console.warn('This method is deprecated please use eth.'+ method.newMethod +'() instead.');
-
- return web3.manager.send({
- method: call,
- params: args,
- outputFormatter: method.outputFormatter,
- inputFormatter: method.inputFormatter
- });
- };
-
- if(objectMethods.length > 1) {
- if(!obj[objectMethods[0]])
- obj[objectMethods[0]] = {};
-
- obj[objectMethods[0]][objectMethods[1]] = callFunction;
-
- } else {
-
- obj[objectMethods[0]] = callFunction;
- }
-
- });
-};
-
-/// creates properties in a given object based on properties description on input
-/// setups api calls for these properties
-var setupProperties = function (obj, properties) {
- properties.forEach(function (property) {
- var proto = {};
- proto.get = function () {
-
- // show deprecated warning
- if(property.newProperty)
- console.warn('This property is deprecated please use eth.'+ 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 eth.'+ property.newProperty +' instead.');
-
- return web3.manager.send({
- method: property.setter,
- params: [val],
- inputFormatter: property.inputFormatter
- });
- };
- }
-
- proto.enumerable = !property.newProperty;
- Object.defineProperty(obj, property.name, proto);
-
- });
-};
-
-/*jshint maxparams:4 */
-var startPolling = function (method, id, callback, uninstall) {
- web3.manager.startPolling({
- method: method,
- params: [id]
- }, id, callback, uninstall);
-};
-/*jshint maxparams:3 */
-
-var stopPolling = function (id) {
- web3.manager.stopPolling(id);
-};
-
-var ethWatch = {
- startPolling: startPolling.bind(null, 'eth_changed'),
- stopPolling: stopPolling
-};
-
-var shhWatch = {
- startPolling: startPolling.bind(null, 'shh_changed'),
- stopPolling: stopPolling
-};
-
-/// setups web3 object, and it's in-browser executed methods
-var web3 = {
- 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 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,
-
- /// used to transform value/string to eth string
- toEth: utils.toEth,
-
- toWei: utils.toWei,
- fromWei: utils.fromWei,
- isAddress: utils.isAddress,
-
-
- /// 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'...)
- /// TODO: fix it, 4 params? no way
- /*jshint maxparams:4 */
- filter: function (fil, eventParams, options, formatter) {
-
- // if its event, treat it differently
- if (fil._isEvent)
- return fil(eventParams, options);
-
- return filter(fil, ethWatch, formatter);
- },
- // DEPRECATED
- watch: function (fil, eventParams, options, formatter) {
- console.warn('eth.watch() is deprecated please use eth.filter() instead.');
- return this.filter(fil, eventParams, options, formatter);
- }
- /*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);
- },
- // DEPRECATED
- watch: function (fil) {
- console.warn('shh.watch() is deprecated please use shh.filter() instead.');
- return this.filter(fil);
- }
- }
-};
-
-/// setups all api methods
-setupMethods(web3, web3Methods());
-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());
-
-module.exports = web3;
-
-
-},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":16,"./watches":17}],"web3":[function(require,module,exports){
+},{}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
-web3.providers.HttpSyncProvider = require('./lib/httpsync');
-web3.providers.QtSyncProvider = require('./lib/qtsync');
-web3.eth.contract = require('./lib/contract');
-web3.abi = require('./lib/abi');
+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;
-},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":18}]},{},["web3"])
+},{"./lib/solidity/abi":1,"./lib/web3":6,"./lib/web3/contract":7,"./lib/web3/httpprovider":13,"./lib/web3/qtsync":16}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index d8b554278..5c188a41e 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -77,6 +77,10 @@ var (
Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM",
}
*/
+ UnlockedAccountFlag = cli.StringFlag{
+ Name: "unlock",
+ Usage: "Unlock a given account untill this programs exits (address:password)",
+ }
VMDebugFlag = cli.BoolFlag{
Name: "vmdebug",
Usage: "Virtual Machine debug output",
diff --git a/core/block_processor.go b/core/block_processor.go
index ea9d06841..7ac8a1bd2 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -80,7 +80,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated
cb := statedb.GetStateObject(coinbase.Address())
st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb)
_, err := st.TransitionState()
- if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) {
+ if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
return nil, nil, err
}
@@ -120,17 +120,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
for _, tx := range txs {
receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
+ if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) {
+ return nil, nil, nil, nil, err
+ }
+
if err != nil {
- switch {
- case IsNonceErr(err):
- return nil, nil, nil, nil, err
- case state.IsGasLimitErr(err):
- return nil, nil, nil, nil, err
- default:
- statelogger.Infoln(err)
- erroneous = append(erroneous, tx)
- err = nil
- }
+ statelogger.Infoln("TX err:", err)
}
receipts = append(receipts, receipt)
handled = append(handled, tx)
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 9dc41f421..97c61395e 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -440,12 +440,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
self.setTotalDifficulty(td)
self.insert(block)
+ /* XXX crashes
jsonlogger.LogJson(&logger.EthChainNewHead{
BlockHash: ethutil.Bytes2Hex(block.Hash()),
BlockNumber: block.Number(),
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
})
+ */
self.setTransState(state.New(block.Root(), self.stateDb))
queue[i] = ChainEvent{block}
diff --git a/core/state_transition.go b/core/state_transition.go
index 9b67de149..7659e3d50 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -184,6 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
}
}
if err = self.UseGas(big.NewInt(dgas)); err != nil {
+ println("2")
return nil, InvalidTxError(err)
}
@@ -198,48 +199,18 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
dataGas.Mul(dataGas, vm.GasCreateByte)
if err := self.UseGas(dataGas); err == nil {
ref.SetCode(ret)
+ } else {
+ statelogger.Infoln("Insufficient gas for creating code. Require", dataGas, "and have", self.gas)
}
}
-
- /*
- if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
- statelogger.Infof("CREATE: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
- // re-run using the JIT (validation for the JIT)
- goodState := vmenv.State().Copy()
- vmenv.state = stateCopy
- vmenv.SetVmType(vm.JitVmTy)
- vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
- statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
- self.state.Set(goodState)
- }
- */
} else {
ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
-
- /*
- if vmenv, ok := vmenv.(*VMEnv); ok && tryJit {
- statelogger.Infof("CALL: re-running using JIT (PH=%x)\n", stateCopy.Root()[:4])
- // re-run using the JIT (validation for the JIT)
- goodState := vmenv.State().Copy()
- vmenv.state = stateCopy
- vmenv.SetVmType(vm.JitVmTy)
- vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
- statelogger.Infof("DONE PH=%x STD_H=%x JIT_H=%x\n", stateCopy.Root()[:4], goodState.Root()[:4], vmenv.State().Root()[:4])
- self.state.Set(goodState)
- }
- */
}
if err != nil && IsValueTransferErr(err) {
return nil, InvalidTxError(err)
}
- /*
- if err != nil {
- self.UseGas(self.gas)
- }
- */
-
return
}
diff --git a/javascript/types.go b/javascript/types.go
index e07267c8f..5f47c1735 100644
--- a/javascript/types.go
+++ b/javascript/types.go
@@ -58,7 +58,7 @@ type JSEthereum struct {
func (self *JSEthereum) Block(v interface{}) otto.Value {
if number, ok := v.(int64); ok {
- return self.toVal(&JSBlock{self.XEth.BlockByNumber(int32(number)), self})
+ return self.toVal(&JSBlock{self.XEth.BlockByNumber(number), self})
} else if hash, ok := v.(string); ok {
return self.toVal(&JSBlock{self.XEth.BlockByHash(hash), self})
}
diff --git a/logger/types.go b/logger/types.go
index d98f0874a..0f70578ba 100644
--- a/logger/types.go
+++ b/logger/types.go
@@ -8,7 +8,12 @@ import (
type utctime8601 struct{}
func (utctime8601) MarshalJSON() ([]byte, error) {
- return []byte(`"` + time.Now().UTC().Format(time.RFC3339Nano)[:26] + `Z"`), nil
+ timestr := time.Now().UTC().Format(time.RFC3339Nano)
+ // Bounds check
+ if len(timestr) > 26 {
+ timestr = timestr[:26]
+ }
+ return []byte(`"` + timestr + `Z"`), nil
}
type JsonLog interface {
diff --git a/miner/worker.go b/miner/worker.go
index 21a0522e8..61091f3c0 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -209,6 +209,8 @@ gasLimit:
err := self.commitTransaction(tx)
switch {
case core.IsNonceErr(err):
+ fallthrough
+ case core.IsInvalidTxErr(err):
// Remove invalid transactions
remove = append(remove, tx)
case state.IsGasLimitErr(err):
@@ -222,7 +224,7 @@ gasLimit:
}
self.eth.TxPool().RemoveSet(remove)
- self.current.coinbase.AddBalance(core.BlockReward)
+ self.current.state.AddBalance(self.coinbase, core.BlockReward)
self.current.state.Update(ethutil.Big0)
self.push()
@@ -258,9 +260,11 @@ func (self *worker) commitUncle(uncle *types.Header) error {
}
func (self *worker) commitTransaction(tx *types.Transaction) error {
+ snap := self.current.state.Copy()
//fmt.Printf("proc %x %v\n", tx.Hash()[:3], tx.Nonce())
receipt, _, err := self.proc.ApplyTransaction(self.current.coinbase, self.current.state, self.current.block, tx, self.current.totalUsedGas, true)
- if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err)) {
+ if err != nil && (core.IsNonceErr(err) || state.IsGasLimitErr(err) || core.IsInvalidTxErr(err)) {
+ self.current.state.Set(snap)
return err
}
diff --git a/rpc/api.go b/rpc/api.go
index d6854bbab..8bbe80bd8 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -1,14 +1,8 @@
-/*
-For each request type, define the following:
-
-1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
-2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct
-3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON
-
-*/
package rpc
import (
+ "encoding/json"
+ "fmt"
"math/big"
"path"
"strings"
@@ -27,8 +21,8 @@ import (
)
var (
- defaultGasPrice = big.NewInt(10000000000000)
- defaultGas = big.NewInt(10000)
+ defaultGasPrice = big.NewInt(150000000000)
+ defaultGas = big.NewInt(500000)
filterTickerTime = 15 * time.Second
)
@@ -50,21 +44,18 @@ type EthereumApi struct {
register map[string][]*NewTxArgs
db ethutil.Database
-
- defaultBlockAge int64
}
func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps"))
api := &EthereumApi{
- eth: eth,
- mux: eth.Backend().EventMux(),
- quit: make(chan struct{}),
- filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
- logs: make(map[int]*logFilter),
- messages: make(map[int]*whisperFilter),
- db: db,
- defaultBlockAge: -1,
+ eth: eth,
+ mux: eth.Backend().EventMux(),
+ quit: make(chan struct{}),
+ filterManager: filter.NewFilterManager(eth.Backend().EventMux()),
+ logs: make(map[int]*logFilter),
+ messages: make(map[int]*whisperFilter),
+ db: db,
}
go api.filterManager.Start()
go api.start()
@@ -72,36 +63,33 @@ func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi {
return api
}
-func (self *EthereumApi) setStateByBlockNumber(num int64) {
+func (self *EthereumApi) xethWithStateNum(num int64) *xeth.XEth {
chain := self.xeth().Backend().ChainManager()
var block *types.Block
- if self.defaultBlockAge < 0 {
+ if num < 0 {
num = chain.CurrentBlock().Number().Int64() + num + 1
}
block = chain.GetBlockByNumber(uint64(num))
+ var st *state.StateDB
if block != nil {
- self.useState(state.New(block.Root(), self.xeth().Backend().StateDb()))
+ st = state.New(block.Root(), self.xeth().Backend().StateDb())
} else {
- self.useState(chain.State())
+ st = chain.State()
}
+ return self.xeth().WithState(st)
+}
+
+func (self *EthereumApi) getStateWithNum(num int64) *xeth.State {
+ return self.xethWithStateNum(num).State()
}
func (self *EthereumApi) start() {
timer := time.NewTicker(filterTickerTime)
- events := self.mux.Subscribe(core.ChainEvent{})
-
done:
for {
select {
- case ev := <-events.Chan():
- switch ev.(type) {
- case core.ChainEvent:
- if self.defaultBlockAge < 0 {
- self.setStateByBlockNumber(self.defaultBlockAge)
- }
- }
case <-timer.C:
self.logMut.Lock()
self.messagesMut.Lock()
@@ -130,35 +118,35 @@ func (self *EthereumApi) stop() {
close(self.quit)
}
-func (self *EthereumApi) Register(args string, reply *interface{}) error {
- self.regmut.Lock()
- defer self.regmut.Unlock()
+// func (self *EthereumApi) Register(args string, reply *interface{}) error {
+// self.regmut.Lock()
+// defer self.regmut.Unlock()
- if _, ok := self.register[args]; ok {
- self.register[args] = nil // register with empty
- }
- return nil
-}
+// if _, ok := self.register[args]; ok {
+// self.register[args] = nil // register with empty
+// }
+// return nil
+// }
-func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
- self.regmut.Lock()
- defer self.regmut.Unlock()
+// func (self *EthereumApi) Unregister(args string, reply *interface{}) error {
+// self.regmut.Lock()
+// defer self.regmut.Unlock()
- delete(self.register, args)
+// delete(self.register, args)
- return nil
-}
+// return nil
+// }
-func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
- self.regmut.Lock()
- defer self.regmut.Unlock()
+// func (self *EthereumApi) WatchTx(args string, reply *interface{}) error {
+// self.regmut.Lock()
+// defer self.regmut.Unlock()
- txs := self.register[args]
- self.register[args] = nil
+// txs := self.register[args]
+// self.register[args] = nil
- *reply = txs
- return nil
-}
+// *reply = txs
+// return nil
+// }
func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error {
var id int
@@ -173,7 +161,7 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
- *reply = id
+ *reply = i2hex(id)
return nil
}
@@ -203,7 +191,7 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
- *reply = id
+ *reply = i2hex(id)
return nil
}
@@ -240,35 +228,49 @@ func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error
return nil
}
-func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
- // This seems a bit precarious Maybe worth splitting to discrete functions
- if len(args.Hash) > 0 {
- *reply = p.xeth().BlockByHash(args.Hash)
- } else {
- *reply = p.xeth().BlockByNumber(args.BlockNumber)
- }
- return nil
-}
+func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) (err error) {
+ // TODO if no_private_key then
+ //if _, exists := p.register[args.From]; exists {
+ // p.register[args.From] = append(p.register[args.From], args)
+ //} else {
+ /*
+ account := accounts.Get(fromHex(args.From))
+ if account != nil {
+ if account.Unlocked() {
+ if !unlockAccount(account) {
+ return
+ }
+ }
-func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
+ result, _ := account.Transact(fromHex(args.To), fromHex(args.Value), fromHex(args.Gas), fromHex(args.GasPrice), fromHex(args.Data))
+ if len(result) > 0 {
+ *reply = toHex(result)
+ }
+ } else if _, exists := p.register[args.From]; exists {
+ p.register[ags.From] = append(p.register[args.From], args)
+ }
+ */
// TODO: align default values to have the same type, e.g. not depend on
// ethutil.Value conversions later on
- if ethutil.Big(args.Gas).Cmp(big.NewInt(0)) == 0 {
- args.Gas = defaultGas.String()
+ if args.Gas.Cmp(big.NewInt(0)) == 0 {
+ args.Gas = defaultGas
}
- if ethutil.Big(args.GasPrice).Cmp(big.NewInt(0)) == 0 {
- args.GasPrice = defaultGasPrice.String()
+ if args.GasPrice.Cmp(big.NewInt(0)) == 0 {
+ args.GasPrice = defaultGasPrice
}
- result, _ := p.xeth().Transact(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data)
- *reply = result
+ *reply, err = p.xeth().Transact(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
+ if err != nil {
+ fmt.Println("err:", err)
+ return err
+ }
return nil
}
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
- result, err := p.xeth().Call(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data)
+ result, err := p.xethWithStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data)
if err != nil {
return err
}
@@ -277,23 +279,28 @@ func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
return nil
}
-func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
- err := args.requirementsPushTx()
- if err != nil {
+func (p *EthereumApi) GetBalance(args *GetBalanceArgs, reply *interface{}) error {
+ if err := args.requirements(); err != nil {
return err
}
- result, _ := p.xeth().PushTx(args.Tx)
- *reply = result
+ state := p.getStateWithNum(args.BlockNumber).SafeGet(args.Address)
+ *reply = toHex(state.Balance().Bytes())
return nil
}
-func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
+func (p *EthereumApi) GetStorage(args *GetStorageArgs, reply *interface{}) error {
+ if err := args.requirements(); err != nil {
return err
}
+ *reply = p.getStateWithNum(args.BlockNumber).SafeGet(args.Address).Storage()
+ return nil
+}
- state := p.xeth().State().SafeGet(args.Address)
+func (p *EthereumApi) GetStorageAt(args *GetStorageAtArgs, reply *interface{}) error {
+ if err := args.requirements(); err != nil {
+ return err
+ }
+ state := p.getStateWithNum(args.BlockNumber).SafeGet(args.Address)
value := state.StorageString(args.Key)
var hx string
@@ -309,115 +316,31 @@ func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error {
return nil
}
-func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
- return err
- }
-
- *reply = p.xeth().State().SafeGet(args.Address).Storage()
- return nil
-}
-
-func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
- *reply = p.xeth().PeerCount()
- return nil
-}
-
-func (p *EthereumApi) GetIsListening(reply *interface{}) error {
- *reply = p.xeth().IsListening()
- return nil
-}
-
-func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
- *reply = p.xeth().Coinbase()
- return nil
-}
-
-func (p *EthereumApi) Accounts(reply *interface{}) error {
- *reply = p.xeth().Accounts()
- return nil
-}
-
-func (p *EthereumApi) GetIsMining(reply *interface{}) error {
- *reply = p.xeth().IsMining()
- return nil
-}
-
-func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error {
- *reply = p.xeth().SetMining(shouldmine)
- return nil
-}
-
-func (p *EthereumApi) GetDefaultBlockAge(reply *interface{}) error {
- *reply = p.defaultBlockAge
- return nil
-}
-
-func (p *EthereumApi) SetDefaultBlockAge(defaultBlockAge int64, reply *interface{}) error {
- p.defaultBlockAge = defaultBlockAge
- p.setStateByBlockNumber(p.defaultBlockAge)
-
- *reply = true
- return nil
-}
-
-func (p *EthereumApi) BlockNumber(reply *interface{}) error {
- *reply = p.xeth().Backend().ChainManager().CurrentBlock().Number()
- return nil
-}
-
func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
err := args.requirements()
if err != nil {
return err
}
- *reply = p.xeth().TxCountAt(args.Address)
+ *reply = p.xethWithStateNum(args.BlockNumber).TxCountAt(args.Address)
return nil
}
-func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
+func (p *EthereumApi) GetData(args *GetDataArgs, reply *interface{}) error {
+ if err := args.requirements(); err != nil {
return err
}
- state := p.xeth().State().SafeGet(args.Address)
- *reply = toHex(state.Balance().Bytes())
- return nil
-}
-
-func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
- return err
- }
- *reply = p.xeth().CodeAt(args.Address)
+ *reply = p.xethWithStateNum(args.BlockNumber).CodeAt(args.Address)
return nil
}
func (p *EthereumApi) GetCompilers(reply *interface{}) error {
- c := []string{"serpent"}
+ c := []string{""}
*reply = c
return nil
}
-func (p *EthereumApi) CompileSerpent(script string, reply *interface{}) error {
- res, err := ethutil.Compile(script, false)
- if err != nil {
- return err
- }
- *reply = res
- return nil
-}
-
-func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error {
- *reply = toHex(crypto.Sha3(fromHex(args.Data)))
- return nil
-}
-
func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
+ if err := args.requirements(); err != nil {
return err
}
@@ -427,8 +350,7 @@ func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error {
}
func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error {
- err := args.requirements()
- if err != nil {
+ if err := args.requirements(); err != nil {
return err
}
@@ -442,14 +364,18 @@ func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error {
return nil
}
-func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) error {
+func (p *EthereumApi) NewWhisperFilter(args *WhisperFilterArgs, reply *interface{}) error {
var id int
- args.Fn = func(msg xeth.WhisperMessage) {
+ opts := new(xeth.Options)
+ opts.From = args.From
+ opts.To = args.To
+ opts.Topics = args.Topics
+ opts.Fn = func(msg xeth.WhisperMessage) {
p.messagesMut.Lock()
defer p.messagesMut.Unlock()
p.messages[id].add(msg) // = append(p.messages[id], msg)
}
- id = p.xeth().Whisper().Watch(args)
+ id = p.xeth().Whisper().Watch(opts)
p.messages[id] = &whisperFilter{timeout: time.Now()}
*reply = id
return nil
@@ -467,7 +393,7 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error {
}
func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error {
- err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl)
+ err := p.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl)
if err != nil {
return err
}
@@ -486,199 +412,358 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
return nil
}
+func (p *EthereumApi) GetBlockByHash(blockhash string, includetx bool) (*BlockRes, error) {
+ block := p.xeth().EthBlockByHash(blockhash)
+ br := NewBlockRes(block)
+ br.fullTx = includetx
+ return br, nil
+}
+
+func (p *EthereumApi) GetBlockByNumber(blocknum int64, includetx bool) (*BlockRes, error) {
+ block := p.xeth().EthBlockByNumber(blocknum)
+ br := NewBlockRes(block)
+ br.fullTx = includetx
+ return br, nil
+}
+
+func (p *EthereumApi) GetBlockTransactionCountByHash(blockhash string) (int64, error) {
+ block := p.xeth().EthBlockByHash(blockhash)
+ br := NewBlockRes(block)
+ return int64(len(br.Transactions)), nil
+}
+
+func (p *EthereumApi) GetBlockTransactionCountByNumber(blocknum int64) (int64, error) {
+ block := p.xeth().EthBlockByNumber(blocknum)
+ br := NewBlockRes(block)
+ return int64(len(br.Transactions)), nil
+}
+
+func (p *EthereumApi) GetBlockUncleCountByHash(blockhash string) (int64, error) {
+ block := p.xeth().EthBlockByHash(blockhash)
+ br := NewBlockRes(block)
+ return int64(len(br.Uncles)), nil
+}
+
+func (p *EthereumApi) GetBlockUncleCountByNumber(blocknum int64) (int64, error) {
+ block := p.xeth().EthBlockByNumber(blocknum)
+ br := NewBlockRes(block)
+ return int64(len(br.Uncles)), nil
+}
+
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
- rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
+ rpclogger.Debugf("%s %s", req.Method, req.Params)
switch req.Method {
+ case "web3_sha3":
+ args := new(Sha3Args)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ *reply = toHex(crypto.Sha3(fromHex(args.Data)))
+ case "net_listening":
+ *reply = p.xeth().IsListening()
+ case "net_peerCount":
+ *reply = toHex(big.NewInt(int64(p.xeth().PeerCount())).Bytes())
case "eth_coinbase":
- return p.GetCoinbase(reply)
- case "eth_listening":
- return p.GetIsListening(reply)
+ *reply = p.xeth().Coinbase()
case "eth_mining":
- return p.GetIsMining(reply)
- case "eth_setMining":
- args, err := req.ToBoolArgs()
- if err != nil {
+ *reply = p.xeth().IsMining()
+ case "eth_gasPrice":
+ *reply = toHex(defaultGasPrice.Bytes())
+ case "eth_accounts":
+ *reply = p.xeth().Accounts()
+ case "eth_blockNumber":
+ *reply = toHex(p.xeth().Backend().ChainManager().CurrentBlock().Number().Bytes())
+ case "eth_getBalance":
+ args := new(GetBalanceArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.SetMining(args, reply)
- case "eth_defaultBlock":
- return p.GetDefaultBlockAge(reply)
- case "eth_setDefaultBlock":
- args, err := req.ToIntArgs()
- if err != nil {
+ return p.GetBalance(args, reply)
+ case "eth_getStorage", "eth_storageAt":
+ args := new(GetStorageArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.SetDefaultBlockAge(int64(args), reply)
- case "eth_peerCount":
- return p.GetPeerCount(reply)
- case "eth_number":
- return p.BlockNumber(reply)
- case "eth_accounts":
- return p.Accounts(reply)
- case "eth_countAt":
- args, err := req.ToGetTxCountArgs()
- if err != nil {
+ return p.GetStorage(args, reply)
+ case "eth_getStorageAt":
+ args := new(GetStorageAtArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.GetStorageAt(args, reply)
+ case "eth_getTransactionCount":
+ args := new(GetTxCountArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.GetTxCountAt(args, reply)
- case "eth_codeAt":
- args, err := req.ToGetCodeAtArgs()
- if err != nil {
+ case "eth_getBlockTransactionCountByHash":
+ args := new(GetBlockByHashArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.GetCodeAt(args, reply)
- case "eth_balanceAt":
- args, err := req.ToGetBalanceArgs()
+
+ v, err := p.GetBlockTransactionCountByHash(args.BlockHash)
if err != nil {
return err
}
- return p.GetBalanceAt(args, reply)
- case "eth_stateAt":
- args, err := req.ToGetStateArgs()
- if err != nil {
+ *reply = toHex(big.NewInt(v).Bytes())
+ case "eth_getBlockTransactionCountByNumber":
+ args := new(GetBlockByNumberArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.GetStateAt(args, reply)
- case "eth_storageAt":
- args, err := req.ToStorageAtArgs()
+
+ v, err := p.GetBlockTransactionCountByNumber(args.BlockNumber)
if err != nil {
return err
}
- return p.GetStorageAt(args, reply)
- case "eth_blockByNumber", "eth_blockByHash":
- args, err := req.ToGetBlockArgs()
+ *reply = toHex(big.NewInt(v).Bytes())
+ case "eth_getUncleCountByBlockHash":
+ args := new(GetBlockByHashArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockUncleCountByHash(args.BlockHash)
if err != nil {
return err
}
- return p.GetBlock(args, reply)
- case "eth_transact":
- args, err := req.ToNewTxArgs()
+ *reply = toHex(big.NewInt(v).Bytes())
+ case "eth_getUncleCountByBlockNumber":
+ args := new(GetBlockByNumberArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockUncleCountByNumber(args.BlockNumber)
if err != nil {
return err
}
+ *reply = toHex(big.NewInt(v).Bytes())
+ case "eth_getData":
+ args := new(GetDataArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.GetData(args, reply)
+ case "eth_sendTransaction", "eth_transact":
+ args := new(NewTxArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
return p.Transact(args, reply)
case "eth_call":
- args, err := req.ToNewTxArgs()
- if err != nil {
+ args := new(NewTxArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.Call(args, reply)
- case "eth_newFilter":
- args, err := req.ToFilterArgs()
- if err != nil {
+ case "eth_flush":
+ return errNotImplemented
+ case "eth_getBlockByHash":
+ args := new(GetBlockByHashArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.NewFilter(args, reply)
- case "eth_newFilterString":
- args, err := req.ToFilterStringArgs()
+
+ v, err := p.GetBlockByHash(args.BlockHash, args.Transactions)
if err != nil {
return err
}
- return p.NewFilterString(args, reply)
- case "eth_uninstallFilter":
- args, err := req.ToUninstallFilterArgs()
+ *reply = v
+ case "eth_getBlockByNumber":
+ args := new(GetBlockByNumberArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockByNumber(args.BlockNumber, args.Transactions)
if err != nil {
return err
}
- return p.UninstallFilter(args, reply)
- case "eth_changed":
- args, err := req.ToIdArgs()
+ *reply = v
+ case "eth_getTransactionByHash":
+ return errNotImplemented
+ case "eth_getTransactionByBlockHashAndIndex":
+ args := new(HashIndexArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockByHash(args.BlockHash, true)
if err != nil {
return err
}
- return p.FilterChanged(args, reply)
- case "eth_filterLogs":
- args, err := req.ToIdArgs()
+ if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
+ return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
+ }
+ *reply = v.Transactions[args.Index]
+ case "eth_getTransactionByBlockNumberAndIndex":
+ args := new(BlockNumIndexArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockByNumber(args.BlockNumber, true)
if err != nil {
return err
}
- return p.Logs(args, reply)
- case "eth_logs":
- args, err := req.ToFilterArgs()
+ if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
+ return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
+ }
+ *reply = v.Transactions[args.Index]
+ case "eth_getUncleByBlockHashAndIndex":
+ args := new(HashIndexArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockByHash(args.BlockHash, false)
if err != nil {
return err
}
- return p.AllLogs(args, reply)
- case "eth_gasPrice":
- *reply = toHex(defaultGasPrice.Bytes())
- return nil
- case "eth_register":
- args, err := req.ToRegisterArgs()
+ if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
+ return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
+ }
+
+ uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
if err != nil {
return err
}
- return p.Register(args, reply)
- case "eth_unregister":
- args, err := req.ToRegisterArgs()
+ *reply = uncle
+ case "eth_getUncleByBlockNumberAndIndex":
+ args := new(BlockNumIndexArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+
+ v, err := p.GetBlockByNumber(args.BlockNumber, true)
if err != nil {
return err
}
- return p.Unregister(args, reply)
- case "eth_watchTx":
- args, err := req.ToWatchTxArgs()
+ if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
+ return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
+ }
+
+ uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
if err != nil {
return err
}
- return p.WatchTx(args, reply)
- case "eth_compilers":
+ *reply = uncle
+ case "eth_getCompilers":
return p.GetCompilers(reply)
- case "eth_serpent":
- args, err := req.ToCompileArgs()
- if err != nil {
+ case "eth_compileSolidity":
+ case "eth_compileLLL":
+ case "eth_compileSerpent":
+ return errNotImplemented
+ case "eth_newFilter":
+ args := new(FilterOptions)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.CompileSerpent(args, reply)
- case "web3_sha3":
- args, err := req.ToSha3Args()
- if err != nil {
+ return p.NewFilter(args, reply)
+ case "eth_newBlockFilter":
+ args := new(FilterStringArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.NewFilterString(args.Word, reply)
+ case "eth_uninstallFilter":
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.Sha3(args, reply)
+ return p.UninstallFilter(args.Id, reply)
+ case "eth_getFilterChanges":
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.FilterChanged(args.Id, reply)
+ case "eth_getFilterLogs":
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.Logs(args.Id, reply)
+ case "eth_getLogs":
+ args := new(FilterOptions)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
+ return err
+ }
+ return p.AllLogs(args, reply)
+ case "eth_getWork":
+ case "eth_submitWork":
+ return errNotImplemented
case "db_put":
- args, err := req.ToDbPutArgs()
- if err != nil {
+ args := new(DbArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.DbPut(args, reply)
case "db_get":
- args, err := req.ToDbGetArgs()
- if err != nil {
+ args := new(DbArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
return p.DbGet(args, reply)
- case "shh_newIdentity":
- return p.NewWhisperIdentity(reply)
- case "shh_newFilter":
- args, err := req.ToWhisperFilterArgs()
- if err != nil {
+ case "shh_post":
+ args := new(WhisperMessageArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.NewWhisperFilter(args, reply)
- case "shh_changed":
- args, err := req.ToIdArgs()
- if err != nil {
+ return p.WhisperPost(args, reply)
+ case "shh_newIdentity":
+ return p.NewWhisperIdentity(reply)
+ case "shh_hasIdentity":
+ args := new(WhisperIdentityArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.MessagesChanged(args, reply)
- case "shh_post":
- args, err := req.ToWhisperPostArgs()
- if err != nil {
+ return p.HasWhisperIdentity(args.Identity, reply)
+ case "shh_newGroup":
+ case "shh_addToGroup":
+ return errNotImplemented
+ case "shh_newFilter":
+ args := new(WhisperFilterArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.WhisperPost(args, reply)
- case "shh_haveIdentity":
- args, err := req.ToWhisperHasIdentityArgs()
- if err != nil {
+ return p.NewWhisperFilter(args, reply)
+ case "shh_uninstallFilter":
+ return errNotImplemented
+ case "shh_getFilterChanges":
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.HasWhisperIdentity(args, reply)
+ return p.MessagesChanged(args.Id, reply)
case "shh_getMessages":
- args, err := req.ToIdArgs()
- if err != nil {
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
- return p.WhisperMessages(args, reply)
+ return p.WhisperMessages(args.Id, reply)
+ // case "eth_register":
+ // args, err := req.ToRegisterArgs()
+ // if err != nil {
+ // return err
+ // }
+ // return p.Register(args, reply)
+ // case "eth_unregister":
+ // args, err := req.ToRegisterArgs()
+ // if err != nil {
+ // return err
+ // }
+ // return p.Unregister(args, reply)
+ // case "eth_watchTx":
+ // args, err := req.ToWatchTxArgs()
+ // if err != nil {
+ // return err
+ // }
+ // return p.WatchTx(args, reply)
default:
return NewErrorWithMessage(errNotImplemented, req.Method)
}
@@ -694,9 +779,38 @@ func (self *EthereumApi) xeth() *xeth.XEth {
return self.eth
}
-func (self *EthereumApi) useState(statedb *state.StateDB) {
- self.xethMu.Lock()
- defer self.xethMu.Unlock()
+func toFilterOptions(options *FilterOptions) core.FilterOptions {
+ var opts core.FilterOptions
+
+ // Convert optional address slice/string to byte slice
+ if str, ok := options.Address.(string); ok {
+ opts.Address = [][]byte{fromHex(str)}
+ } else if slice, ok := options.Address.([]interface{}); ok {
+ bslice := make([][]byte, len(slice))
+ for i, addr := range slice {
+ if saddr, ok := addr.(string); ok {
+ bslice[i] = fromHex(saddr)
+ }
+ }
+ opts.Address = bslice
+ }
+
+ opts.Earliest = options.Earliest
+ opts.Latest = options.Latest
+
+ topics := make([][][]byte, len(options.Topics))
+ for i, topicDat := range options.Topics {
+ if slice, ok := topicDat.([]interface{}); ok {
+ topics[i] = make([][]byte, len(slice))
+ for j, topic := range slice {
+ topics[i][j] = fromHex(topic.(string))
+ }
+ } else if str, ok := topicDat.(string); ok {
+ topics[i] = make([][]byte, 1)
+ topics[i][0] = fromHex(str)
+ }
+ }
+ opts.Topics = topics
- self.eth = self.eth.UseState(statedb)
+ return opts
}
diff --git a/rpc/api_test.go b/rpc/api_test.go
index a9fc16cd3..ec03822c5 100644
--- a/rpc/api_test.go
+++ b/rpc/api_test.go
@@ -1,11 +1,29 @@
package rpc
import (
+ "encoding/json"
"sync"
"testing"
"time"
)
+func TestWeb3Sha3(t *testing.T) {
+ jsonstr := `{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}`
+ expected := "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
+
+ api := &EthereumApi{}
+
+ var req RpcRequest
+ json.Unmarshal([]byte(jsonstr), &req)
+
+ var response interface{}
+ _ = api.GetRequestReply(&req, &response)
+
+ if response.(string) != expected {
+ t.Errorf("Expected %s got %s", expected, response)
+ }
+}
+
func TestFilterClose(t *testing.T) {
t.Skip()
api := &EthereumApi{
diff --git a/rpc/args.go b/rpc/args.go
index ec3359a4a..d4d807060 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -1,247 +1,331 @@
package rpc
-import "encoding/json"
+import (
+ "bytes"
+ "encoding/json"
+ "math/big"
-import "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/ethutil"
+)
-type GetBlockArgs struct {
- BlockNumber int32
- Hash string
-}
-
-func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
- argint, argstr := int32(0), ""
- if err = json.Unmarshal(b, &argint); err == nil {
- obj.BlockNumber = argint
- return
+func blockNumber(raw json.RawMessage, number *int64) (err error) {
+ var str string
+ if err = json.Unmarshal(raw, &str); err != nil {
+ return errDecodeArgs
}
- if err = json.Unmarshal(b, &argstr); err == nil {
- obj.Hash = argstr
- return
+
+ switch str {
+ case "latest":
+ *number = -1
+ case "pending":
+ *number = 0
+ default:
+ *number = ethutil.String2Big(str).Int64()
}
- return errDecodeArgs
+ return nil
}
-type NewTxArgs struct {
- From string `json:"from"`
- Pass string `json:"pass"`
- To string `json:"to"`
- Value string `json:"value"`
- Gas string `json:"gas"`
- GasPrice string `json:"gasPrice"`
- Data string `json:"data"`
-}
-
-func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
- // Data can be either specified as "data" or "code" :-/
- var ext struct {
- From string
- To string
- Value string
- Gas string
- GasPrice string
- Data string
- Code string
+type GetBlockByHashArgs struct {
+ BlockHash string
+ Transactions bool
+}
+
+func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errArguments
}
- if err = json.Unmarshal(b, &ext); err == nil {
- if len(ext.Data) == 0 {
- ext.Data = ext.Code
- }
- obj.From = ext.From
- obj.To = ext.To
- obj.Value = ext.Value
- obj.Gas = ext.Gas
- obj.GasPrice = ext.GasPrice
- obj.Data = ext.Data
+ argstr, ok := obj[0].(string)
+ if !ok {
+ return errDecodeArgs
+ }
+ args.BlockHash = argstr
- return
+ if len(obj) > 1 {
+ args.Transactions = obj[1].(bool)
}
- return errDecodeArgs
+ return nil
}
-type PushTxArgs struct {
- Tx string `json:"tx"`
+type GetBlockByNumberArgs struct {
+ BlockNumber int64
+ Transactions bool
}
-func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) {
- arg0 := ""
- if err = json.Unmarshal(b, &arg0); err == nil {
- obj.Tx = arg0
- return
+func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errArguments
}
- return errDecodeArgs
+
+ if v, ok := obj[0].(float64); ok {
+ args.BlockNumber = int64(v)
+ } else {
+ args.BlockNumber = ethutil.Big(obj[0].(string)).Int64()
+ }
+
+ if len(obj) > 1 {
+ args.Transactions = obj[1].(bool)
+ }
+
+ return nil
+}
+
+type NewTxArgs struct {
+ From string
+ To string
+ Value *big.Int
+ Gas *big.Int
+ GasPrice *big.Int
+ Data string
+
+ BlockNumber int64
}
-func (a *PushTxArgs) requirementsPushTx() error {
- if a.Tx == "" {
- return NewErrorWithMessage(errArguments, "PushTx requires a 'tx' as argument")
+func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj struct{ From, To, Value, Gas, GasPrice, Data string }
+ if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
+ return err
}
+
+ args.From = obj.From
+ args.To = obj.To
+ args.Value = ethutil.Big(obj.Value)
+ args.Gas = ethutil.Big(obj.Gas)
+ args.GasPrice = ethutil.Big(obj.GasPrice)
+ args.Data = obj.Data
+
return nil
}
type GetStorageArgs struct {
- Address string
+ Address string
+ BlockNumber int64
}
-func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
- if err = json.Unmarshal(b, &obj.Address); err != nil {
+func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
- return
+
+ return nil
}
-func (a *GetStorageArgs) requirements() error {
- if len(a.Address) == 0 {
- return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
+func (args *GetStorageArgs) requirements() error {
+ if len(args.Address) == 0 {
+ return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
-type GetStateArgs struct {
- Address string
- Key string
+type GetStorageAtArgs struct {
+ Address string
+ Key string
+ BlockNumber int64
}
-func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) {
- arg0 := ""
- if err = json.Unmarshal(b, &arg0); err == nil {
- obj.Address = arg0
- return
+func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []string
+ if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
+ return errDecodeArgs
+ }
+ if len(obj) < 2 {
+ return errDecodeArgs
}
- return errDecodeArgs
+
+ args.Address = obj[0]
+ args.Key = obj[1]
+
+ return nil
}
-func (a *GetStateArgs) requirements() error {
- if a.Address == "" {
- return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'address' value as argument")
+func (args *GetStorageAtArgs) requirements() error {
+ if len(args.Address) == 0 {
+ return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
- if a.Key == "" {
- return NewErrorWithMessage(errArguments, "GetStorageAt requires an 'key' value as argument")
+
+ if len(args.Key) == 0 {
+ return NewErrorWithMessage(errArguments, "Key cannot be blank")
}
return nil
}
type GetTxCountArgs struct {
- Address string `json:"address"`
+ Address string
+ BlockNumber int64
}
-func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
- arg0 := ""
- if err = json.Unmarshal(b, &arg0); err == nil {
- obj.Address = arg0
- return
+func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
+ return errDecodeArgs
}
- return errDecodeArgs
+
+ return nil
}
-func (a *GetTxCountArgs) requirements() error {
- if a.Address == "" {
- return NewErrorWithMessage(errArguments, "GetTxCountAt requires an 'address' value as argument")
+func (args *GetTxCountArgs) requirements() error {
+ if len(args.Address) == 0 {
+ return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
type GetBalanceArgs struct {
- Address string
+ Address string
+ BlockNumber int64
}
-func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
- arg0 := ""
- if err = json.Unmarshal(b, &arg0); err == nil {
- obj.Address = arg0
- return
+func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
+ return errDecodeArgs
}
- return errDecodeArgs
+
+ return nil
}
-func (a *GetBalanceArgs) requirements() error {
- if a.Address == "" {
- return NewErrorWithMessage(errArguments, "GetBalanceAt requires an 'address' value as argument")
+func (args *GetBalanceArgs) requirements() error {
+ if len(args.Address) == 0 {
+ return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
-type GetCodeAtArgs struct {
- Address string
+type GetDataArgs struct {
+ Address string
+ BlockNumber int64
}
-func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) {
- arg0 := ""
- if err = json.Unmarshal(b, &arg0); err == nil {
- obj.Address = arg0
- return
+func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
+ return errDecodeArgs
}
- return errDecodeArgs
+
+ return nil
}
-func (a *GetCodeAtArgs) requirements() error {
- if a.Address == "" {
- return NewErrorWithMessage(errArguments, "GetCodeAt requires an 'address' value as argument")
+func (args *GetDataArgs) requirements() error {
+ if len(args.Address) == 0 {
+ return NewErrorWithMessage(errArguments, "Address cannot be blank")
}
return nil
}
+type BlockNumIndexArgs struct {
+ BlockNumber int64
+ Index int64
+}
+
+type HashIndexArgs struct {
+ BlockHash string
+ Index int64
+}
+
type Sha3Args struct {
Data string
}
-func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) {
- if err = json.Unmarshal(b, &obj.Data); err != nil {
- return errDecodeArgs
+func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return NewErrorWithMessage(errDecodeArgs, err.Error())
}
- return
+
+ if len(obj) < 1 {
+ return errArguments
+ }
+ args.Data = obj[0].(string)
+
+ return nil
}
+// type FilterArgs struct {
+// FromBlock uint64
+// ToBlock uint64
+// Limit uint64
+// Offset uint64
+// Address string
+// Topics []string
+// }
+
+// func (args *FilterArgs) UnmarshalJSON(b []byte) (err error) {
+// var obj []struct {
+// FromBlock string `json:"fromBlock"`
+// ToBlock string `json:"toBlock"`
+// Limit string `json:"limit"`
+// Offset string `json:"offset"`
+// Address string `json:"address"`
+// Topics []string `json:"topics"`
+// }
+
+// if err = json.Unmarshal(b, &obj); err != nil {
+// return errDecodeArgs
+// }
+
+// if len(obj) < 1 {
+// return errArguments
+// }
+// args.FromBlock = uint64(ethutil.Big(obj[0].FromBlock).Int64())
+// args.ToBlock = uint64(ethutil.Big(obj[0].ToBlock).Int64())
+// args.Limit = uint64(ethutil.Big(obj[0].Limit).Int64())
+// args.Offset = uint64(ethutil.Big(obj[0].Offset).Int64())
+// args.Address = obj[0].Address
+// args.Topics = obj[0].Topics
+
+// return nil
+// }
+
type FilterOptions struct {
Earliest int64
Latest int64
Address interface{}
- Topic []interface{}
+ Topics []interface{}
Skip int
Max int
}
-func toFilterOptions(options *FilterOptions) core.FilterOptions {
- var opts core.FilterOptions
-
- // Convert optional address slice/string to byte slice
- if str, ok := options.Address.(string); ok {
- opts.Address = [][]byte{fromHex(str)}
- } else if slice, ok := options.Address.([]interface{}); ok {
- bslice := make([][]byte, len(slice))
- for i, addr := range slice {
- if saddr, ok := addr.(string); ok {
- bslice[i] = fromHex(saddr)
- }
- }
- opts.Address = bslice
+func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
+ var obj []struct {
+ FromBlock string `json:"fromBlock"`
+ ToBlock string `json:"toBlock"`
+ Limit string `json:"limit"`
+ Offset string `json:"offset"`
+ Address string `json:"address"`
+ Topics []interface{} `json:"topics"`
}
- opts.Earliest = options.Earliest
- opts.Latest = options.Latest
+ if err = json.Unmarshal(b, &obj); err != nil {
+ return errDecodeArgs
+ }
- topics := make([][][]byte, len(options.Topic))
- for i, topicDat := range options.Topic {
- if slice, ok := topicDat.([]interface{}); ok {
- topics[i] = make([][]byte, len(slice))
- for j, topic := range slice {
- topics[i][j] = fromHex(topic.(string))
- }
- } else if str, ok := topicDat.(string); ok {
- topics[i] = make([][]byte, 1)
- topics[i][0] = fromHex(str)
- }
+ if len(obj) < 1 {
+ return errArguments
}
- opts.Topics = topics
+ args.Earliest = int64(ethutil.Big(obj[0].FromBlock).Int64())
+ args.Latest = int64(ethutil.Big(obj[0].ToBlock).Int64())
+ args.Max = int(ethutil.Big(obj[0].Limit).Int64())
+ args.Skip = int(ethutil.Big(obj[0].Offset).Int64())
+ args.Address = obj[0].Address
+ args.Topics = obj[0].Topics
- return opts
+ return nil
}
-type FilterChangedArgs struct {
- n int
-}
+// type FilterChangedArgs struct {
+// n int
+// }
type DbArgs struct {
Database string
@@ -249,12 +333,32 @@ type DbArgs struct {
Value string
}
+func (args *DbArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 2 {
+ return errArguments
+ }
+ args.Database = obj[0].(string)
+ args.Key = obj[1].(string)
+
+ if len(obj) > 2 {
+ args.Value = obj[2].(string)
+ }
+
+ return nil
+}
+
func (a *DbArgs) requirements() error {
if len(a.Database) == 0 {
- return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Database' value as argument")
+ return NewErrorWithMessage(errArguments, "Database cannot be blank")
}
if len(a.Key) == 0 {
- return NewErrorWithMessage(errArguments, "DbPutArgs requires an 'Key' value as argument")
+ return NewErrorWithMessage(errArguments, "Key cannot be blank")
}
return nil
}
@@ -263,7 +367,140 @@ type WhisperMessageArgs struct {
Payload string
To string
From string
- Topic []string
+ Topics []string
Priority uint32
Ttl uint32
}
+
+func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []struct {
+ Payload string
+ To string
+ From string
+ Topics []string
+ Priority string
+ Ttl string
+ }
+
+ if err = json.Unmarshal(b, &obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errArguments
+ }
+ args.Payload = obj[0].Payload
+ args.To = obj[0].To
+ args.From = obj[0].From
+ args.Topics = obj[0].Topics
+ args.Priority = uint32(ethutil.Big(obj[0].Priority).Int64())
+ args.Ttl = uint32(ethutil.Big(obj[0].Ttl).Int64())
+
+ return nil
+}
+
+type CompileArgs struct {
+ Source string
+}
+
+func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []interface{}
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) > 0 {
+ args.Source = obj[0].(string)
+ }
+
+ return nil
+}
+
+type FilterStringArgs struct {
+ Word string
+}
+
+func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []string
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errDecodeArgs
+ }
+
+ args.Word = obj[0]
+
+ return nil
+}
+
+type FilterIdArgs struct {
+ Id int
+}
+
+func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []string
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errDecodeArgs
+ }
+
+ args.Id = int(ethutil.Big(obj[0]).Int64())
+
+ return nil
+}
+
+type WhisperIdentityArgs struct {
+ Identity string
+}
+
+func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []string
+ r := bytes.NewReader(b)
+ if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errDecodeArgs
+ }
+
+ args.Identity = obj[0]
+
+ return nil
+}
+
+type WhisperFilterArgs struct {
+ To string `json:"to"`
+ From string
+ Topics []string
+}
+
+func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
+ var obj []struct {
+ To string
+ From string
+ Topics []string
+ }
+
+ if err = json.Unmarshal(b, &obj); err != nil {
+ return errDecodeArgs
+ }
+
+ if len(obj) < 1 {
+ return errArguments
+ }
+
+ args.To = obj[0].To
+ args.From = obj[0].From
+ args.Topics = obj[0].Topics
+
+ return nil
+}
diff --git a/rpc/args_test.go b/rpc/args_test.go
new file mode 100644
index 000000000..027624500
--- /dev/null
+++ b/rpc/args_test.go
@@ -0,0 +1,434 @@
+package rpc
+
+import (
+ "bytes"
+ "encoding/json"
+ "math/big"
+ "testing"
+)
+
+func TestSha3(t *testing.T) {
+ input := `["0x68656c6c6f20776f726c64"]`
+ expected := "0x68656c6c6f20776f726c64"
+
+ args := new(Sha3Args)
+ json.Unmarshal([]byte(input), &args)
+
+ if args.Data != expected {
+ t.Error("got %s expected %s", input, expected)
+ }
+}
+
+func TestGetBalanceArgs(t *testing.T) {
+ input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x1f"]`
+ expected := new(GetBalanceArgs)
+ expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
+ expected.BlockNumber = 31
+
+ args := new(GetBalanceArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if args.Address != expected.Address {
+ t.Errorf("Address should be %v but is %v", expected.Address, args.Address)
+ }
+
+ if args.BlockNumber != expected.BlockNumber {
+ t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber)
+ }
+}
+
+func TestGetBlockByHashArgs(t *testing.T) {
+ input := `["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true]`
+ expected := new(GetBlockByHashArgs)
+ expected.BlockHash = "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
+ expected.Transactions = true
+
+ args := new(GetBlockByHashArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if args.BlockHash != expected.BlockHash {
+ t.Errorf("BlockHash should be %v but is %v", expected.BlockHash, args.BlockHash)
+ }
+
+ if args.Transactions != expected.Transactions {
+ t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions)
+ }
+}
+
+func TestGetBlockByNumberArgs(t *testing.T) {
+ input := `["0x1b4", false]`
+ expected := new(GetBlockByNumberArgs)
+ expected.BlockNumber = 436
+ expected.Transactions = false
+
+ args := new(GetBlockByNumberArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if args.BlockNumber != expected.BlockNumber {
+ t.Errorf("BlockHash should be %v but is %v", expected.BlockNumber, args.BlockNumber)
+ }
+
+ if args.Transactions != expected.Transactions {
+ t.Errorf("Transactions should be %v but is %v", expected.Transactions, args.Transactions)
+ }
+}
+
+func TestNewTxArgs(t *testing.T) {
+ input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
+ "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
+ "gas": "0x76c0",
+ "gasPrice": "0x9184e72a000",
+ "value": "0x9184e72a000",
+ "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}]`
+ expected := new(NewTxArgs)
+ expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155"
+ expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675"
+ expected.Gas = big.NewInt(30400)
+ expected.GasPrice = big.NewInt(10000000000000)
+ expected.Value = big.NewInt(10000000000000)
+ expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
+
+ args := new(NewTxArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.From != args.From {
+ t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
+ }
+
+ if expected.To != args.To {
+ t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
+ }
+
+ if bytes.Compare(expected.Gas.Bytes(), args.Gas.Bytes()) != 0 {
+ t.Errorf("Gas shoud be %#v but is %#v", expected.Gas.Bytes(), args.Gas.Bytes())
+ }
+
+ if bytes.Compare(expected.GasPrice.Bytes(), args.GasPrice.Bytes()) != 0 {
+ t.Errorf("GasPrice shoud be %#v but is %#v", expected.GasPrice, args.GasPrice)
+ }
+
+ if bytes.Compare(expected.Value.Bytes(), args.Value.Bytes()) != 0 {
+ t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value)
+ }
+
+ if expected.Data != args.Data {
+ t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data)
+ }
+}
+
+func TestGetStorageArgs(t *testing.T) {
+ input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
+ expected := new(GetStorageArgs)
+ expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
+ expected.BlockNumber = -1
+
+ args := new(GetStorageArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Address != args.Address {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ if expected.BlockNumber != args.BlockNumber {
+ t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
+ }
+}
+
+func TestGetStorageAtArgs(t *testing.T) {
+ input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"]`
+ expected := new(GetStorageAtArgs)
+ expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
+ expected.Key = "0x0"
+ expected.BlockNumber = 2
+
+ args := new(GetStorageAtArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Address != args.Address {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ if expected.Key != args.Key {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ if expected.BlockNumber != args.BlockNumber {
+ t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
+ }
+}
+
+func TestGetTxCountArgs(t *testing.T) {
+ input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]`
+ expected := new(GetTxCountArgs)
+ expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
+ expected.BlockNumber = -1
+
+ args := new(GetTxCountArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Address != args.Address {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ if expected.BlockNumber != args.BlockNumber {
+ t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
+ }
+}
+
+func TestGetDataArgs(t *testing.T) {
+ input := `["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8", "latest"]`
+ expected := new(GetDataArgs)
+ expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
+ expected.BlockNumber = -1
+
+ args := new(GetDataArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Address != args.Address {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ if expected.BlockNumber != args.BlockNumber {
+ t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber)
+ }
+}
+
+func TestFilterOptions(t *testing.T) {
+ input := `[{
+ "fromBlock": "0x1",
+ "toBlock": "0x2",
+ "limit": "0x3",
+ "offset": "0x0",
+ "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
+ "topics": ["0x12341234"]}]`
+ expected := new(FilterOptions)
+ expected.Earliest = 1
+ expected.Latest = 2
+ expected.Max = 3
+ expected.Skip = 0
+ expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
+ // expected.Topics = []string{"0x12341234"}
+
+ args := new(FilterOptions)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Earliest != args.Earliest {
+ t.Errorf("Earliest shoud be %#v but is %#v", expected.Earliest, args.Earliest)
+ }
+
+ if expected.Latest != args.Latest {
+ t.Errorf("Latest shoud be %#v but is %#v", expected.Latest, args.Latest)
+ }
+
+ if expected.Max != args.Max {
+ t.Errorf("Max shoud be %#v but is %#v", expected.Max, args.Max)
+ }
+
+ if expected.Skip != args.Skip {
+ t.Errorf("Skip shoud be %#v but is %#v", expected.Skip, args.Skip)
+ }
+
+ if expected.Address != args.Address {
+ t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+ }
+
+ // if expected.Topics != args.Topics {
+ // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic)
+ // }
+}
+
+func TestDbArgs(t *testing.T) {
+ input := `["0x74657374","0x6b6579","0x6d79537472696e67"]`
+ expected := new(DbArgs)
+ expected.Database = "0x74657374"
+ expected.Key = "0x6b6579"
+ expected.Value = "0x6d79537472696e67"
+
+ args := new(DbArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if err := args.requirements(); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Database != args.Database {
+ t.Errorf("Database shoud be %#v but is %#v", expected.Database, args.Database)
+ }
+
+ if expected.Key != args.Key {
+ t.Errorf("Key shoud be %#v but is %#v", expected.Key, args.Key)
+ }
+
+ if expected.Value != args.Value {
+ t.Errorf("Value shoud be %#v but is %#v", expected.Value, args.Value)
+ }
+}
+
+func TestWhisperMessageArgs(t *testing.T) {
+ input := `[{"from":"0xc931d93e97ab07fe42d923478ba2465f2",
+ "topics": ["0x68656c6c6f20776f726c64"],
+ "payload":"0x68656c6c6f20776f726c64",
+ "ttl": "0x64",
+ "priority": "0x64"}]`
+ expected := new(WhisperMessageArgs)
+ expected.From = "0xc931d93e97ab07fe42d923478ba2465f2"
+ expected.To = ""
+ expected.Payload = "0x68656c6c6f20776f726c64"
+ expected.Priority = 100
+ expected.Ttl = 100
+ expected.Topics = []string{"0x68656c6c6f20776f726c64"}
+
+ args := new(WhisperMessageArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.From != args.From {
+ t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
+ }
+
+ if expected.To != args.To {
+ t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
+ }
+
+ if expected.Payload != args.Payload {
+ t.Errorf("Value shoud be %#v but is %#v", expected.Payload, args.Payload)
+ }
+
+ if expected.Ttl != args.Ttl {
+ t.Errorf("Ttl shoud be %#v but is %#v", expected.Ttl, args.Ttl)
+ }
+
+ if expected.Priority != args.Priority {
+ t.Errorf("Priority shoud be %#v but is %#v", expected.Priority, args.Priority)
+ }
+
+ // if expected.Topics != args.Topics {
+ // t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic)
+ // }
+}
+
+func TestFilterIdArgs(t *testing.T) {
+ input := `["0x7"]`
+ expected := new(FilterIdArgs)
+ expected.Id = 7
+
+ args := new(FilterIdArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Id != args.Id {
+ t.Errorf("Id shoud be %#v but is %#v", expected.Id, args.Id)
+ }
+}
+
+func TestWhsiperFilterArgs(t *testing.T) {
+ input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": "0x34ag445g3455b34"}]`
+ expected := new(WhisperFilterArgs)
+ expected.From = ""
+ expected.To = "0x34ag445g3455b34"
+ expected.Topics = []string{"0x68656c6c6f20776f726c64"}
+
+ args := new(WhisperFilterArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.From != args.From {
+ t.Errorf("From shoud be %#v but is %#v", expected.From, args.From)
+ }
+
+ if expected.To != args.To {
+ t.Errorf("To shoud be %#v but is %#v", expected.To, args.To)
+ }
+
+ // if expected.Topics != args.Topics {
+ // t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+ // }
+}
+
+func TestCompileArgs(t *testing.T) {
+ input := `["contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"]`
+ expected := new(CompileArgs)
+ expected.Source = `contract test { function multiply(uint a) returns(uint d) { return a * 7; } }`
+
+ args := new(CompileArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Source != args.Source {
+ t.Errorf("Source shoud be %#v but is %#v", expected.Source, args.Source)
+ }
+}
+
+func TestFilterStringArgs(t *testing.T) {
+ input := `["pending"]`
+ expected := new(FilterStringArgs)
+ expected.Word = "pending"
+
+ args := new(FilterStringArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Word != args.Word {
+ t.Errorf("Word shoud be %#v but is %#v", expected.Word, args.Word)
+ }
+}
+
+func TestWhisperIdentityArgs(t *testing.T) {
+ input := `["0xc931d93e97ab07fe42d923478ba2465f283"]`
+ expected := new(WhisperIdentityArgs)
+ expected.Identity = "0xc931d93e97ab07fe42d923478ba2465f283"
+
+ args := new(WhisperIdentityArgs)
+ if err := json.Unmarshal([]byte(input), &args); err != nil {
+ t.Error(err)
+ }
+
+ if expected.Identity != args.Identity {
+ t.Errorf("Identity shoud be %#v but is %#v", expected.Identity, args.Identity)
+ }
+}
diff --git a/rpc/messages.go b/rpc/messages.go
index b37d8229d..a3ebbf330 100644
--- a/rpc/messages.go
+++ b/rpc/messages.go
@@ -17,12 +17,9 @@
package rpc
import (
- "bytes"
"encoding/json"
"errors"
"fmt"
-
- "github.com/ethereum/go-ethereum/xeth"
)
var (
@@ -33,10 +30,10 @@ var (
)
type RpcRequest struct {
- ID interface{} `json:"id"`
- JsonRpc string `json:"jsonrpc"`
- Method string `json:"method"`
- Params []json.RawMessage `json:"params"`
+ ID interface{} `json:"id"`
+ JsonRpc string `json:"jsonrpc"`
+ Method string `json:"method"`
+ Params json.RawMessage `json:"params"`
}
type RpcSuccessResponse struct {
@@ -61,359 +58,30 @@ func NewErrorWithMessage(err error, msg string) error {
return fmt.Errorf("%s: %s", err.Error(), msg)
}
-func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(Sha3Args)
- r := bytes.NewReader(req.Params[0])
- if err := json.NewDecoder(r).Decode(args); err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetBlockArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(NewTxArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(PushTxArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetStateArgs)
- // TODO need to pass both arguments
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetStorageArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetTxCountArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetBalanceArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(GetCodeAtArgs)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToBoolArgs() (bool, error) {
- if len(req.Params) < 1 {
- return false, errArguments
- }
-
- var args bool
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return false, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToIntArgs() (int, error) {
- if len(req.Params) < 1 {
- return 0, errArguments
- }
-
- var args int
- if err := json.Unmarshal(req.Params[0], &args); err != nil {
- return 0, errArguments
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToCompileArgs() (string, error) {
- if len(req.Params) < 1 {
- return "", errArguments
- }
-
- var args string
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return "", errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- args := new(FilterOptions)
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(args)
- if err != nil {
- return nil, errDecodeArgs
- }
- return args, nil
-}
-
-func (req *RpcRequest) ToFilterStringArgs() (string, error) {
- if len(req.Params) < 1 {
- return "", errArguments
- }
-
- var args string
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return "", errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToUninstallFilterArgs() (int, error) {
- if len(req.Params) < 1 {
- return 0, errArguments
- }
-
- var args int
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return 0, errDecodeArgs
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToFilterChangedArgs() (int, error) {
- if len(req.Params) < 1 {
- return 0, errArguments
- }
-
- var id int
- r := bytes.NewReader(req.Params[0])
- err := json.NewDecoder(r).Decode(&id)
- if err != nil {
- return 0, errDecodeArgs
- }
- return id, nil
-}
-
-func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) {
- if len(req.Params) < 3 {
- return nil, errArguments
- }
-
- var args DbArgs
- err := json.Unmarshal(req.Params[0], &args.Database)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
- err = json.Unmarshal(req.Params[1], &args.Key)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
- err = json.Unmarshal(req.Params[2], &args.Value)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
-
- return &args, nil
-}
-
-func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) {
- if len(req.Params) < 2 {
- return nil, errArguments
- }
+// func (req *RpcRequest) ToRegisterArgs() (string, error) {
+// if len(req.Params) < 1 {
+// return "", errArguments
+// }
- var args DbArgs
- err := json.Unmarshal(req.Params[0], &args.Database)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
+// var args string
+// err := json.Unmarshal(req.Params, &args)
+// if err != nil {
+// return "", err
+// }
- err = json.Unmarshal(req.Params[1], &args.Key)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
+// return args, nil
+// }
- return &args, nil
-}
-
-func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- var args xeth.Options
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return nil, NewErrorWithMessage(errDecodeArgs, err.Error())
- }
-
- return &args, nil
-}
-
-func (req *RpcRequest) ToIdArgs() (int, error) {
- if len(req.Params) < 1 {
- return 0, errArguments
- }
+// func (req *RpcRequest) ToWatchTxArgs() (string, error) {
+// if len(req.Params) < 1 {
+// return "", errArguments
+// }
- var id int
- err := json.Unmarshal(req.Params[0], &id)
- if err != nil {
- return 0, errDecodeArgs
- }
-
- return id, nil
-}
-
-func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) {
- if len(req.Params) < 1 {
- return nil, errArguments
- }
-
- var args WhisperMessageArgs
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return nil, err
- }
-
- return &args, nil
-}
+// var args string
+// err := json.Unmarshal(req.Params, &args)
+// if err != nil {
+// return "", err
+// }
-func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) {
- if len(req.Params) < 1 {
- return "", errArguments
- }
-
- var args string
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return "", err
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToRegisterArgs() (string, error) {
- if len(req.Params) < 1 {
- return "", errArguments
- }
-
- var args string
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return "", err
- }
-
- return args, nil
-}
-
-func (req *RpcRequest) ToWatchTxArgs() (string, error) {
- if len(req.Params) < 1 {
- return "", errArguments
- }
-
- var args string
- err := json.Unmarshal(req.Params[0], &args)
- if err != nil {
- return "", err
- }
-
- return args, nil
-}
+// return args, nil
+// }
diff --git a/rpc/responses.go b/rpc/responses.go
new file mode 100644
index 000000000..f41ce7b96
--- /dev/null
+++ b/rpc/responses.go
@@ -0,0 +1,212 @@
+package rpc
+
+import (
+ "encoding/json"
+ // "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+type BlockRes struct {
+ fullTx bool
+
+ BlockNumber int64 `json:"number"`
+ BlockHash []byte `json:"hash"`
+ ParentHash []byte `json:"parentHash"`
+ Nonce []byte `json:"nonce"`
+ Sha3Uncles []byte `json:"sha3Uncles"`
+ LogsBloom []byte `json:"logsBloom"`
+ TransactionRoot []byte `json:"transactionRoot"`
+ StateRoot []byte `json:"stateRoot"`
+ Miner []byte `json:"miner"`
+ Difficulty int64 `json:"difficulty"`
+ TotalDifficulty int64 `json:"totalDifficulty"`
+ Size int64 `json:"size"`
+ ExtraData []byte `json:"extraData"`
+ GasLimit int64 `json:"gasLimit"`
+ MinGasPrice int64 `json:"minGasPrice"`
+ GasUsed int64 `json:"gasUsed"`
+ UnixTimestamp int64 `json:"timestamp"`
+ Transactions []*TransactionRes `json:"transactions"`
+ Uncles [][]byte `json:"uncles"`
+}
+
+func (b *BlockRes) MarshalJSON() ([]byte, error) {
+ var ext struct {
+ BlockNumber string `json:"number"`
+ BlockHash string `json:"hash"`
+ ParentHash string `json:"parentHash"`
+ Nonce string `json:"nonce"`
+ Sha3Uncles string `json:"sha3Uncles"`
+ LogsBloom string `json:"logsBloom"`
+ TransactionRoot string `json:"transactionRoot"`
+ StateRoot string `json:"stateRoot"`
+ Miner string `json:"miner"`
+ Difficulty string `json:"difficulty"`
+ TotalDifficulty string `json:"totalDifficulty"`
+ Size string `json:"size"`
+ ExtraData string `json:"extraData"`
+ GasLimit string `json:"gasLimit"`
+ MinGasPrice string `json:"minGasPrice"`
+ GasUsed string `json:"gasUsed"`
+ UnixTimestamp string `json:"timestamp"`
+ Transactions []interface{} `json:"transactions"`
+ Uncles []string `json:"uncles"`
+ }
+
+ // convert strict types to hexified strings
+ ext.BlockNumber = toHex(big.NewInt(b.BlockNumber).Bytes())
+ ext.BlockHash = toHex(b.BlockHash)
+ ext.ParentHash = toHex(b.ParentHash)
+ ext.Nonce = toHex(b.Nonce)
+ ext.Sha3Uncles = toHex(b.Sha3Uncles)
+ ext.LogsBloom = toHex(b.LogsBloom)
+ ext.TransactionRoot = toHex(b.TransactionRoot)
+ ext.StateRoot = toHex(b.StateRoot)
+ ext.Miner = toHex(b.Miner)
+ ext.Difficulty = toHex(big.NewInt(b.Difficulty).Bytes())
+ ext.TotalDifficulty = toHex(big.NewInt(b.TotalDifficulty).Bytes())
+ ext.Size = toHex(big.NewInt(b.Size).Bytes())
+ // ext.ExtraData = toHex(b.ExtraData)
+ ext.GasLimit = toHex(big.NewInt(b.GasLimit).Bytes())
+ // ext.MinGasPrice = toHex(big.NewInt(b.MinGasPrice).Bytes())
+ ext.GasUsed = toHex(big.NewInt(b.GasUsed).Bytes())
+ ext.UnixTimestamp = toHex(big.NewInt(b.UnixTimestamp).Bytes())
+ ext.Transactions = make([]interface{}, len(b.Transactions))
+ if b.fullTx {
+ for i, tx := range b.Transactions {
+ ext.Transactions[i] = tx
+ }
+ } else {
+ for i, tx := range b.Transactions {
+ ext.Transactions[i] = toHex(tx.Hash)
+ }
+ }
+ ext.Uncles = make([]string, len(b.Uncles))
+ for i, v := range b.Uncles {
+ ext.Uncles[i] = toHex(v)
+ }
+
+ return json.Marshal(ext)
+}
+
+func NewBlockRes(block *types.Block) *BlockRes {
+ if block == nil {
+ return &BlockRes{}
+ }
+
+ res := new(BlockRes)
+ res.BlockNumber = block.Number().Int64()
+ res.BlockHash = block.Hash()
+ res.ParentHash = block.ParentHash()
+ res.Nonce = block.Header().Nonce
+ res.Sha3Uncles = block.Header().UncleHash
+ res.LogsBloom = block.Bloom()
+ res.TransactionRoot = block.Header().TxHash
+ res.StateRoot = block.Root()
+ res.Miner = block.Header().Coinbase
+ res.Difficulty = block.Difficulty().Int64()
+ if block.Td != nil {
+ res.TotalDifficulty = block.Td.Int64()
+ }
+ res.Size = int64(block.Size())
+ // res.ExtraData =
+ res.GasLimit = block.GasLimit().Int64()
+ // res.MinGasPrice =
+ res.GasUsed = block.GasUsed().Int64()
+ res.UnixTimestamp = block.Time()
+ res.Transactions = make([]*TransactionRes, len(block.Transactions()))
+ for i, tx := range block.Transactions() {
+ v := NewTransactionRes(tx)
+ v.BlockHash = block.Hash()
+ v.BlockNumber = block.Number().Int64()
+ v.TxIndex = int64(i)
+ res.Transactions[i] = v
+ }
+ res.Uncles = make([][]byte, len(block.Uncles()))
+ for i, uncle := range block.Uncles() {
+ res.Uncles[i] = uncle.Hash()
+ }
+ return res
+}
+
+type TransactionRes struct {
+ Hash []byte `json:"hash"`
+ Nonce int64 `json:"nonce"`
+ BlockHash []byte `json:"blockHash,omitempty"`
+ BlockNumber int64 `json:"blockNumber,omitempty"`
+ TxIndex int64 `json:"transactionIndex,omitempty"`
+ From []byte `json:"from"`
+ To []byte `json:"to"`
+ Value int64 `json:"value"`
+ Gas int64 `json:"gas"`
+ GasPrice int64 `json:"gasPrice"`
+ Input []byte `json:"input"`
+}
+
+func (t *TransactionRes) MarshalJSON() ([]byte, error) {
+ var ext struct {
+ Hash string `json:"hash"`
+ Nonce string `json:"nonce"`
+ BlockHash string `json:"blockHash,omitempty"`
+ BlockNumber string `json:"blockNumber,omitempty"`
+ TxIndex string `json:"transactionIndex,omitempty"`
+ From string `json:"from"`
+ To string `json:"to"`
+ Value string `json:"value"`
+ Gas string `json:"gas"`
+ GasPrice string `json:"gasPrice"`
+ Input string `json:"input"`
+ }
+
+ ext.Hash = toHex(t.Hash)
+ ext.Nonce = toHex(big.NewInt(t.Nonce).Bytes())
+ ext.BlockHash = toHex(t.BlockHash)
+ ext.BlockNumber = toHex(big.NewInt(t.BlockNumber).Bytes())
+ ext.TxIndex = toHex(big.NewInt(t.TxIndex).Bytes())
+ ext.From = toHex(t.From)
+ ext.To = toHex(t.To)
+ ext.Value = toHex(big.NewInt(t.Value).Bytes())
+ ext.Gas = toHex(big.NewInt(t.Gas).Bytes())
+ ext.GasPrice = toHex(big.NewInt(t.GasPrice).Bytes())
+ ext.Input = toHex(t.Input)
+
+ return json.Marshal(ext)
+}
+
+func NewTransactionRes(tx *types.Transaction) *TransactionRes {
+ var v = new(TransactionRes)
+ v.Hash = tx.Hash()
+ v.Nonce = int64(tx.Nonce())
+ v.From = tx.From()
+ v.To = tx.To()
+ v.Value = tx.Value().Int64()
+ v.Gas = tx.Gas().Int64()
+ v.GasPrice = tx.GasPrice().Int64()
+ v.Input = tx.Data()
+ return v
+}
+
+type FilterLogRes struct {
+ Hash string `json:"hash"`
+ Address string `json:"address"`
+ Data string `json:"data"`
+ BlockNumber string `json:"blockNumber"`
+ TransactionHash string `json:"transactionHash"`
+ BlockHash string `json:"blockHash"`
+ TransactionIndex string `json:"transactionIndex"`
+ LogIndex string `json:"logIndex"`
+}
+
+type FilterWhisperRes struct {
+ Hash string `json:"hash"`
+ From string `json:"from"`
+ To string `json:"to"`
+ Expiry string `json:"expiry"`
+ Sent string `json:"sent"`
+ Ttl string `json:"ttl"`
+ Topics string `json:"topics"`
+ Payload string `json:"payload"`
+ WorkProved string `json:"workProved"`
+}
diff --git a/rpc/util.go b/rpc/util.go
index 3e8ca3fef..8ff3c6d31 100644
--- a/rpc/util.go
+++ b/rpc/util.go
@@ -18,8 +18,11 @@ package rpc
import (
"encoding/json"
+ "fmt"
"io"
+ "math/big"
"net/http"
+ "reflect"
"time"
"github.com/ethereum/go-ethereum/ethutil"
@@ -32,9 +35,63 @@ var rpclogger = logger.NewLogger("RPC")
type JsonWrapper struct{}
+// Unmarshal state is a helper method which has the ability to decode messsages
+// that use the `defaultBlock` (https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter)
+// For example a `call`: [{to: "0x....", data:"0x..."}, "latest"]. The first argument is the transaction
+// message and the second one refers to the block height (or state) to which to apply this `call`.
+func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error) {
+ var data []json.RawMessage
+ if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
+ return errDecodeArgs
+ }
+
+ // Number index determines the index in the array for a possible block number
+ numberIndex := 0
+
+ value := reflect.ValueOf(iface)
+ rvalue := reflect.Indirect(value)
+
+ switch rvalue.Kind() {
+ case reflect.Slice:
+ // This is a bit of a cheat, but `data` is expected to be larger than 2 if iface is a slice
+ if number != nil {
+ numberIndex = len(data) - 1
+ } else {
+ numberIndex = len(data)
+ }
+
+ slice := reflect.MakeSlice(rvalue.Type(), numberIndex, numberIndex)
+ for i, raw := range data[0:numberIndex] {
+ v := slice.Index(i).Interface()
+ if err = json.Unmarshal(raw, &v); err != nil {
+ fmt.Println(err, v)
+ return err
+ }
+ slice.Index(i).Set(reflect.ValueOf(v))
+ }
+ reflect.Indirect(rvalue).Set(slice) //value.Set(slice)
+ case reflect.Struct:
+ fallthrough
+ default:
+ if err = json.Unmarshal(data[0], iface); err != nil {
+ return errDecodeArgs
+ }
+ numberIndex = 1
+ }
+
+ // <0 index means out of bound for block number
+ if numberIndex >= 0 && len(data) > numberIndex {
+ if err = blockNumber(data[numberIndex], number); err != nil {
+ return errDecodeArgs
+ }
+ }
+
+ return nil
+}
+
func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) {
var payload []byte
- payload, err = json.Marshal(v)
+ payload, err = json.MarshalIndent(v, "", "\t")
if err != nil {
rpclogger.Fatalln("Error marshalling JSON", err)
return 0, err
@@ -63,18 +120,31 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error)
}
func toHex(b []byte) string {
- return "0x" + ethutil.Bytes2Hex(b)
+ hex := ethutil.Bytes2Hex(b)
+ // Prefer output of "0x0" instead of "0x"
+ if len(hex) == 0 {
+ hex = "0"
+ }
+ return "0x" + hex
}
+
func fromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" {
s = s[2:]
}
+ if len(s)%2 == 1 {
+ s = "0" + s
+ }
return ethutil.Hex2Bytes(s)
}
return nil
}
+func i2hex(n int) string {
+ return toHex(big.NewInt(int64(n)).Bytes())
+}
+
type RpcServer interface {
Start()
Stop()
diff --git a/rpc/util_test.go b/rpc/util_test.go
new file mode 100644
index 000000000..b0a4979b5
--- /dev/null
+++ b/rpc/util_test.go
@@ -0,0 +1,25 @@
+package rpc
+
+import (
+ "bytes"
+ "testing"
+)
+
+//fromHex
+func TestFromHex(t *testing.T) {
+ input := "0x01"
+ expected := []byte{1}
+ result := fromHex(input)
+ if bytes.Compare(expected, result) != 0 {
+ t.Errorf("Expected % x got % x", expected, result)
+ }
+}
+
+func TestFromHexOddLength(t *testing.T) {
+ input := "0x1"
+ expected := []byte{1}
+ result := fromHex(input)
+ if bytes.Compare(expected, result) != 0 {
+ t.Errorf("Expected % x got % x", expected, result)
+ }
+}
diff --git a/vm/vm.go b/vm/vm.go
index 6f3945472..6e4a54844 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -37,7 +37,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
context := NewContext(caller, me, code, gas, price)
- vmlogger.Debugf("(%d) (%x) %x (code=%d) gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData)
+ self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl()
if self.Recoverable {
// Recover from any require exception
@@ -696,7 +696,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
if err != nil {
stack.push(ethutil.BigFalse)
- vmlogger.Debugln(err)
+ self.Printf("%v").Endl()
} else {
stack.push(ethutil.BigTrue)
@@ -726,7 +726,7 @@ func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.I
return context.Return(nil), nil
default:
- vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op)
+ self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
panic(fmt.Errorf("Invalid opcode %x", op))
}
@@ -894,7 +894,7 @@ func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
func (self *Vm) Endl() VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
- vmlogger.Debugln(self.logStr)
+ vmlogger.Infoln(self.logStr)
self.logStr = ""
}
}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index 60262bf17..d8dd66aec 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -98,7 +98,7 @@ func New(eth Backend, frontend Frontend) *XEth {
}
func (self *XEth) Backend() Backend { return self.eth }
-func (self *XEth) UseState(statedb *state.StateDB) *XEth {
+func (self *XEth) WithState(statedb *state.StateDB) *XEth {
xeth := &XEth{
eth: self.eth,
blockProcessor: self.blockProcessor,
@@ -122,7 +122,14 @@ func (self *XEth) BlockByHash(strHash string) *Block {
return NewBlock(block)
}
-func (self *XEth) BlockByNumber(num int32) *Block {
+func (self *XEth) EthBlockByHash(strHash string) *types.Block {
+ hash := fromHex(strHash)
+ block := self.chainManager.GetBlock(hash)
+
+ return block
+}
+
+func (self *XEth) BlockByNumber(num int64) *Block {
if num == -1 {
return NewBlock(self.chainManager.CurrentBlock())
}
@@ -130,13 +137,21 @@ func (self *XEth) BlockByNumber(num int32) *Block {
return NewBlock(self.chainManager.GetBlockByNumber(uint64(num)))
}
+func (self *XEth) EthBlockByNumber(num int64) *types.Block {
+ if num == -1 {
+ return self.chainManager.CurrentBlock()
+ }
+
+ return self.chainManager.GetBlockByNumber(uint64(num))
+}
+
func (self *XEth) Block(v interface{}) *Block {
if n, ok := v.(int32); ok {
- return self.BlockByNumber(n)
+ return self.BlockByNumber(int64(n))
} else if str, ok := v.(string); ok {
return self.BlockByHash(str)
} else if f, ok := v.(float64); ok { // Don't ask ...
- return self.BlockByNumber(int32(f))
+ return self.BlockByNumber(int64(f))
}
return nil
@@ -278,14 +293,12 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
return toHex(tx.Hash()), nil
}
-func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
- if len(gasStr) == 0 {
- gasStr = "100000"
- }
- if len(gasPriceStr) == 0 {
- gasPriceStr = "1"
- }
+var (
+ defaultGasPrice = big.NewInt(10000000000000)
+ defaultGas = big.NewInt(90000)
+)
+func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, error) {
statedb := self.State().State() //self.chainManager.TransState()
msg := callmsg{
from: statedb.GetOrNewStateObject(fromHex(fromStr)),
@@ -295,6 +308,14 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
value: ethutil.Big(valueStr),
data: fromHex(dataStr),
}
+ if msg.gas.Cmp(big.NewInt(0)) == 0 {
+ msg.gas = defaultGas
+ }
+
+ if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
+ msg.gasPrice = defaultGasPrice
+ }
+
block := self.chainManager.CurrentBlock()
vmenv := core.NewEnv(statedb, self.chainManager, msg, block)
@@ -327,7 +348,7 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
}
- state := self.chainManager.TransState()
+ state := self.chainManager.TxState()
nonce := state.GetNonce(from)
tx.SetNonce(nonce)