diff --git a/cmd/mist/assets/examples/coin.html b/cmd/mist/assets/examples/coin.html
index 115145c4c..b6bab682f 100644
--- a/cmd/mist/assets/examples/coin.html
+++ b/cmd/mist/assets/examples/coin.html
@@ -77,7 +77,8 @@
}
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 += "
"+item+" | "+web3.toDecimal(storage[item])+" |
";
diff --git a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
index 7b2531677..c0b37641c 100644
--- a/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
+++ b/cmd/mist/assets/ext/ethereum.js/dist/ethereum.js
@@ -1684,7 +1684,7 @@ var methods = [
inputFormatter: [utils.toHex, function(param){ return (!param) ? false : true; }]},
{ name: 'getUncle', call: uncleCall,
outputFormatter: formatters.outputBlockFormatter,
- inputFormatter: [utils.toHex, function(param){ return (!param) ? false : true; }]},
+ inputFormatter: [utils.toHex, utils.toHex, function(param){ return (!param) ? false : true; }]},
{ name: 'getCompilers', call: 'eth_getCompilers' },
{ name: 'getBlockTransactionCount', call: getBlockTransactionCountCall,
outputFormatter: utils.toDecimal,
@@ -1703,9 +1703,9 @@ var methods = [
inputFormatter: formatters.inputTransactionFormatter },
{ name: 'call', call: 'eth_call', addDefaultblock: 2,
inputFormatter: formatters.inputCallFormatter },
- { name: 'compile.solidity', call: 'eth_compileSolidity' },
- { name: 'compile.lll', call: 'eth_compileLLL' },
- { name: 'compile.serpent', call: 'eth_compileSerpent' },
+ { 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
@@ -1939,12 +1939,34 @@ var getOptions = function (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.topic instanceof Array) {
- options.topic = options.topic.map(function(topic){
+ if(options.topics instanceof Array) {
+ options.topics = options.topics.map(function(topic){
return utils.toHex(topic);
});
}
@@ -1952,13 +1974,13 @@ var getOptions = function (options) {
// 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
};
};
@@ -2269,6 +2291,7 @@ if ("build" !== 'build') {/*
*/}
var HttpProvider = function (host) {
+ this.name = 'HTTP';
this.handlers = [];
this.host = host || 'http://localhost:8080';
};
@@ -2280,8 +2303,14 @@ HttpProvider.prototype.send = function (payload, callback) {
// ASYNC
if(typeof callback === 'function') {
request.onreadystatechange = function() {
- if(request.readyState === 4 && request.status === 200) {
- callback(JSON.parse(request.responseText));
+ if(request.readyState === 4) {
+ var result = '';
+ try {
+ result = JSON.parse(request.responseText)
+ } catch(error) {
+ result = error;
+ }
+ callback(result, request.status);
}
};
@@ -2518,19 +2547,26 @@ var requestManager = function() {
return null;
}
- // ASYNC (only when callback is given, and it a HttpProvidor)
- if(typeof callback === 'function' && provider.host){
- provider.send(payload, function(result){
+ // 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)) {
- console.log(result);
- if(typeof result === 'object' && result.error && result.error.message)
+ 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((typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result);
+ callback(null, (typeof data.outputFormatter === 'function') ? data.outputFormatter(result.result) : result.result);
});
// SYNC
diff --git a/rpc/api.go b/rpc/api.go
index dc0945d19..c03168863 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -165,7 +165,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
}
@@ -417,7 +417,7 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
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.Infof("%s %s", req.Method, req.Params)
switch req.Method {
case "web3_sha3":
args := new(Sha3Args)
@@ -446,7 +446,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err
}
return p.GetBalance(args, reply)
- case "eth_getStorage":
+ case "eth_getStorage", "eth_storageAt":
// TODO handle BlockNumber
args := new(GetStorageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
diff --git a/rpc/args.go b/rpc/args.go
index 887d63d46..3d4c8667a 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -3,32 +3,26 @@ package rpc
import (
"bytes"
"encoding/json"
+ "fmt"
"math/big"
"github.com/ethereum/go-ethereum/ethutil"
)
-// 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 unmarshalState(b []byte, iface interface{}, str *string) (err error) {
- var data []json.RawMessage
- if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
+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(data[0], iface); err != nil {
- return errDecodeArgs
- }
-
- // Second argument is optional (transact doesn't require it)
- if len(data) > 1 {
- if err = json.Unmarshal(data[1], str); err != nil {
- return errDecodeArgs
- }
+ switch str {
+ case "latest":
+ *number = -1
+ case "pending":
+ *number = 0
+ default:
+ *number = ethutil.String2Big(str).Int64()
}
-
return nil
}
@@ -88,20 +82,12 @@ type NewTxArgs struct {
GasPrice *big.Int
Data string
- BlockHeight string
+ BlockNumber int64
}
func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
- var obj struct {
- From string `json:"from"`
- To string `json:"to"`
- Value string `json:"value"`
- Gas string `json:"gas"`
- GasPrice string `json:"gasPrice"`
- Data string `json:"data"`
- }
- var height string
- if err = unmarshalState(b, &obj, &height); err != nil {
+ var obj struct{ From, To, Value, Gas, GasPrice, Data string }
+ if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return err
}
@@ -111,7 +97,6 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
args.Gas = ethutil.Big(obj.Gas)
args.GasPrice = ethutil.Big(obj.GasPrice)
args.Data = obj.Data
- args.BlockHeight = height
return nil
}
@@ -122,24 +107,10 @@ type GetStorageArgs struct {
}
func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
- var obj []interface{}
- r := bytes.NewReader(b)
- if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
-
- if len(obj) < 1 {
- return errArguments
- }
- args.Address = obj[0].(string)
-
- if len(obj) > 1 {
- if obj[1].(string) == "latest" {
- args.BlockNumber = -1
- } else {
- args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
- }
- }
+ fmt.Println(args)
return nil
}
@@ -158,25 +129,18 @@ type GetStorageAtArgs struct {
}
func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
- var obj []interface{}
- r := bytes.NewReader(b)
- if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ var obj []string
+ if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return errDecodeArgs
}
-
if len(obj) < 2 {
- return errArguments
+ return errDecodeArgs
}
- args.Address = obj[0].(string)
- args.Key = obj[1].(string)
- if len(obj) > 2 {
- if obj[2].(string) == "latest" {
- args.BlockNumber = -1
- } else {
- args.BlockNumber = ethutil.Big(obj[2].(string)).Int64()
- }
- }
+ args.Address = obj[0]
+ args.Key = obj[1]
+
+ fmt.Println(args)
return nil
}
@@ -198,26 +162,10 @@ type GetTxCountArgs struct {
}
func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
- var obj []interface{}
- r := bytes.NewReader(b)
- if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
- if len(obj) < 1 {
- return errArguments
-
- }
- args.Address = obj[0].(string)
-
- if len(obj) > 1 {
- if obj[1].(string) == "latest" {
- args.BlockNumber = -1
- } else {
- args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
- }
- }
-
return nil
}
@@ -234,25 +182,10 @@ type GetBalanceArgs struct {
}
func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
- var obj []interface{}
- r := bytes.NewReader(b)
- if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
- if len(obj) < 1 {
- return errArguments
- }
- args.Address = obj[0].(string)
-
- if len(obj) > 1 {
- if obj[1].(string) == "latest" {
- args.BlockNumber = -1
- } else {
- args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
- }
- }
-
return nil
}
@@ -269,25 +202,10 @@ type GetDataArgs struct {
}
func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
- var obj []interface{}
- r := bytes.NewReader(b)
- if err := json.NewDecoder(r).Decode(&obj); err != nil {
+ if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
- if len(obj) < 1 {
- return errArguments
- }
- args.Address = obj[0].(string)
-
- if len(obj) > 1 {
- if obj[1].(string) == "latest" {
- args.BlockNumber = -1
- } else {
- args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
- }
- }
-
return nil
}
diff --git a/rpc/util.go b/rpc/util.go
index 69c7b629f..fb4efdb45 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,6 +35,60 @@ 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)
@@ -80,6 +137,10 @@ func fromHex(s string) []byte {
return nil
}
+func i2hex(n int) string {
+ return toHex(big.NewInt(int64(n)).Bytes())
+}
+
type RpcServer interface {
Start()
Stop()