| 
									
										
										
										
											2015-01-13 09:13:43 -06:00
										 |  |  | /* | 
					
						
							|  |  |  | 	This file is part of go-ethereum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | 	it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | 	the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | 	(at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go-ethereum 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 General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | 	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | package rpc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2015-02-20 12:59:54 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-02-04 15:05:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethutil" | 
					
						
							| 
									
										
										
										
											2015-02-04 15:05:47 -08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 	"github.com/ethereum/go-ethereum/state" | 
					
						
							| 
									
										
										
										
											2015-02-20 12:59:54 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/xeth" | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | var rpclogger = logger.NewLogger("RPC") | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | type JsonWrapper struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2015-03-12 19:07:03 -05:00
										 |  |  | 		return NewDecodeParamError(err.Error()) | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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 { | 
					
						
							| 
									
										
										
										
											2015-03-12 19:07:03 -05:00
										 |  |  | 			return NewDecodeParamError(err.Error()) | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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 { | 
					
						
							| 
									
										
										
										
											2015-03-12 19:07:03 -05:00
										 |  |  | 			return NewDecodeParamError(err.Error()) | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 	var payload []byte | 
					
						
							| 
									
										
										
										
											2015-03-10 19:10:02 -05:00
										 |  |  | 	payload, err = json.MarshalIndent(v, "", "\t") | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | 		rpclogger.Fatalln("Error marshalling JSON", err) | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 		return 0, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-04 15:05:47 -08:00
										 |  |  | 	rpclogger.DebugDetailf("Sending payload: %s", payload) | 
					
						
							| 
									
										
										
										
											2014-10-21 13:24:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return writer.Write(payload) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 	var reqParsed RpcRequest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Convert JSON to native types | 
					
						
							|  |  |  | 	d := json.NewDecoder(req.Body) | 
					
						
							|  |  |  | 	defer req.Body.Close() | 
					
						
							|  |  |  | 	err := d.Decode(&reqParsed) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | 		rpclogger.Errorln("Error decoding JSON: ", err) | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 		return reqParsed, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-11 11:56:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-25 14:50:43 -06:00
										 |  |  | 	rpclogger.DebugDetailf("Parsed request: %s", reqParsed) | 
					
						
							| 
									
										
										
										
											2015-01-12 23:25:29 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return reqParsed, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | func toHex(b []byte) string { | 
					
						
							| 
									
										
										
										
											2015-03-04 14:13:31 -06:00
										 |  |  | 	hex := ethutil.Bytes2Hex(b) | 
					
						
							|  |  |  | 	// Prefer output of "0x0" instead of "0x" | 
					
						
							|  |  |  | 	if len(hex) == 0 { | 
					
						
							|  |  |  | 		hex = "0" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return "0x" + hex | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-10 19:10:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-10 20:14:38 +01:00
										 |  |  | func i2hex(n int) string { | 
					
						
							|  |  |  | 	return toHex(big.NewInt(int64(n)).Bytes()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | type RpcServer interface { | 
					
						
							|  |  |  | 	Start() | 
					
						
							|  |  |  | 	Stop() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Log struct { | 
					
						
							|  |  |  | 	Address string   `json:"address"` | 
					
						
							| 
									
										
										
										
											2015-02-24 16:18:27 +01:00
										 |  |  | 	Topic   []string `json:"topic"` | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 	Data    string   `json:"data"` | 
					
						
							| 
									
										
										
										
											2015-02-22 13:24:26 +01:00
										 |  |  | 	Number  uint64   `json:"number"` | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func toLogs(logs state.Logs) (ls []Log) { | 
					
						
							|  |  |  | 	ls = make([]Log, len(logs)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, log := range logs { | 
					
						
							|  |  |  | 		var l Log | 
					
						
							| 
									
										
										
										
											2015-02-19 11:51:38 +01:00
										 |  |  | 		l.Topic = make([]string, len(log.Topics())) | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 		l.Address = toHex(log.Address()) | 
					
						
							|  |  |  | 		l.Data = toHex(log.Data()) | 
					
						
							| 
									
										
										
										
											2015-02-22 13:24:26 +01:00
										 |  |  | 		l.Number = log.Number() | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 		for j, topic := range log.Topics() { | 
					
						
							| 
									
										
										
										
											2015-02-19 11:51:38 +01:00
										 |  |  | 			l.Topic[j] = toHex(topic) | 
					
						
							| 
									
										
										
										
											2015-01-29 11:39:59 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		ls[i] = l | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-20 12:59:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | type whisperFilter struct { | 
					
						
							|  |  |  | 	messages []xeth.WhisperMessage | 
					
						
							|  |  |  | 	timeout  time.Time | 
					
						
							| 
									
										
										
										
											2015-02-23 15:43:41 +01:00
										 |  |  | 	id       int | 
					
						
							| 
									
										
										
										
											2015-02-20 12:59:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) { | 
					
						
							|  |  |  | 	w.messages = append(w.messages, msgs...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (w *whisperFilter) get() []xeth.WhisperMessage { | 
					
						
							|  |  |  | 	w.timeout = time.Now() | 
					
						
							|  |  |  | 	tmp := w.messages | 
					
						
							|  |  |  | 	w.messages = nil | 
					
						
							|  |  |  | 	return tmp | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type logFilter struct { | 
					
						
							|  |  |  | 	logs    state.Logs | 
					
						
							|  |  |  | 	timeout time.Time | 
					
						
							| 
									
										
										
										
											2015-02-23 15:43:41 +01:00
										 |  |  | 	id      int | 
					
						
							| 
									
										
										
										
											2015-02-20 12:59:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (l *logFilter) add(logs ...state.Log) { | 
					
						
							|  |  |  | 	l.logs = append(l.logs, logs...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (l *logFilter) get() state.Logs { | 
					
						
							|  |  |  | 	l.timeout = time.Now() | 
					
						
							|  |  |  | 	tmp := l.logs | 
					
						
							|  |  |  | 	l.logs = nil | 
					
						
							|  |  |  | 	return tmp | 
					
						
							|  |  |  | } |