util.go 5.01 KB
Newer Older
obscuren's avatar
obscuren committed
1
/*
2
  This file is part of go-ethereum
obscuren's avatar
obscuren committed
3

4 5 6 7
  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.
obscuren's avatar
obscuren committed
8

9 10 11 12
  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.
obscuren's avatar
obscuren committed
13

14 15
  You should have received a copy of the GNU General Public License
  along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
obscuren's avatar
obscuren committed
16
*/
17
package websocket
obscuren's avatar
obscuren committed
18 19

import (
20 21
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/types"
zelig's avatar
zelig committed
22
	"github.com/ethereum/go-ethereum/eth"
23
	"github.com/ethereum/go-ethereum/ethutil"
24 25
	"github.com/ethereum/go-ethereum/event/filter"
	"github.com/ethereum/go-ethereum/state"
obscuren's avatar
obscuren committed
26
	"github.com/ethereum/go-ethereum/ui"
27
	"github.com/ethereum/go-ethereum/xeth"
obscuren's avatar
obscuren committed
28 29 30 31 32 33 34
)

func args(v ...interface{}) []interface{} {
	return v
}

type WebSocketServer struct {
35 36
	eth           *eth.Ethereum
	filterManager *filter.FilterManager
obscuren's avatar
obscuren committed
37 38 39
}

func NewWebSocketServer(eth *eth.Ethereum) *WebSocketServer {
40 41 42 43
	filterManager := filter.NewFilterManager(eth.EventMux())
	go filterManager.Start()

	return &WebSocketServer{eth, filterManager}
obscuren's avatar
obscuren committed
44 45 46
}

func (self *WebSocketServer) Serv() {
47
	pipe := xeth.NewJSXEth(self.eth)
obscuren's avatar
obscuren committed
48

49 50
	wsServ := NewServer("/eth", ":40404")
	wsServ.MessageFunc(func(c *Client, msg *Message) {
obscuren's avatar
obscuren committed
51 52 53 54 55
		switch msg.Call {
		case "compile":
			data := ethutil.NewValue(msg.Args)
			bcode, err := ethutil.Compile(data.Get(0).Str(), false)
			if err != nil {
56
				c.Write(args(nil, err.Error()), msg.Id)
obscuren's avatar
obscuren committed
57 58 59
			}

			code := ethutil.Bytes2Hex(bcode)
60 61
			c.Write(args(code, nil), msg.Id)
		case "eth_blockByNumber":
obscuren's avatar
obscuren committed
62 63 64
			args := msg.Arguments()

			block := pipe.BlockByNumber(int32(args.Get(0).Uint()))
65
			c.Write(block, msg.Id)
obscuren's avatar
obscuren committed
66

67 68 69 70 71 72
		case "eth_blockByHash":
			args := msg.Arguments()

			c.Write(pipe.BlockByHash(args.Get(0).Str()), msg.Id)

		case "eth_transact":
obscuren's avatar
obscuren committed
73 74 75
			if mp, ok := msg.Args[0].(map[string]interface{}); ok {
				object := mapToTxParams(mp)
				c.Write(
76 77
					args(pipe.Transact(pipe.Key().PrivateKey, object["to"], object["value"], object["gas"], object["gasPrice"], object["data"])),
					msg.Id,
obscuren's avatar
obscuren committed
78 79 80
				)

			}
81 82 83 84
		case "eth_gasPrice":
			c.Write("10000000000000", msg.Id)
		case "eth_coinbase":
			c.Write(pipe.CoinBase(), msg.Id)
obscuren's avatar
obscuren committed
85

86 87
		case "eth_listening":
			c.Write(pipe.IsListening(), msg.Id)
obscuren's avatar
obscuren committed
88

89 90
		case "eth_mining":
			c.Write(pipe.IsMining(), msg.Id)
obscuren's avatar
obscuren committed
91

92 93
		case "eth_peerCount":
			c.Write(pipe.PeerCount(), msg.Id)
obscuren's avatar
obscuren committed
94

95
		case "eth_countAt":
obscuren's avatar
obscuren committed
96 97
			args := msg.Arguments()

98
			c.Write(pipe.TxCountAt(args.Get(0).Str()), msg.Id)
obscuren's avatar
obscuren committed
99

100
		case "eth_codeAt":
obscuren's avatar
obscuren committed
101 102
			args := msg.Arguments()

103
			c.Write(len(pipe.CodeAt(args.Get(0).Str())), msg.Id)
obscuren's avatar
obscuren committed
104

105
		case "eth_storageAt":
obscuren's avatar
obscuren committed
106 107
			args := msg.Arguments()

108
			c.Write(pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()), msg.Id)
obscuren's avatar
obscuren committed
109

110
		case "eth_balanceAt":
obscuren's avatar
obscuren committed
111 112
			args := msg.Arguments()

113
			c.Write(pipe.BalanceAt(args.Get(0).Str()), msg.Id)
obscuren's avatar
obscuren committed
114

115 116
		case "eth_accounts":
			c.Write(pipe.Accounts(), msg.Id)
obscuren's avatar
obscuren committed
117

118
		case "eth_newFilter":
119 120
			if mp, ok := msg.Args[0].(map[string]interface{}); ok {
				var id int
obscuren's avatar
obscuren committed
121
				filter := ui.NewFilterFromMap(mp, self.eth)
122 123 124 125 126 127
				filter.MessageCallback = func(messages state.Messages) {
					c.Event(toMessages(messages), "eth_changed", id)
				}
				id = self.filterManager.InstallFilter(filter)
				c.Write(id, msg.Id)
			}
128
		case "eth_newFilterString":
129 130 131 132 133 134 135 136 137 138 139 140
			var id int
			filter := core.NewFilter(self.eth)
			filter.BlockCallback = func(block *types.Block) {
				c.Event(nil, "eth_changed", id)
			}
			id = self.filterManager.InstallFilter(filter)
			c.Write(id, msg.Id)
		case "eth_filterLogs":
			filter := self.filterManager.GetFilter(int(msg.Arguments().Get(0).Uint()))
			if filter != nil {
				c.Write(toMessages(filter.Find()), msg.Id)
			}
obscuren's avatar
obscuren committed
141 142 143 144 145 146 147
		}

	})

	wsServ.Listen()
}

148 149 150 151 152 153 154 155 156
func toMessages(messages state.Messages) (msgs []xeth.JSMessage) {
	msgs = make([]xeth.JSMessage, len(messages))
	for i, msg := range messages {
		msgs[i] = xeth.NewJSMessage(msg)
	}

	return
}

obscuren's avatar
obscuren committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
// TODO This is starting to become a generic method. Move to utils
func mapToTxParams(object map[string]interface{}) map[string]string {
	// Default values
	if object["from"] == nil {
		object["from"] = ""
	}
	if object["to"] == nil {
		object["to"] = ""
	}
	if object["value"] == nil {
		object["value"] = ""
	}
	if object["gas"] == nil {
		object["gas"] = ""
	}
	if object["gasPrice"] == nil {
		object["gasPrice"] = ""
	}

	var dataStr string
	var data []string
	if str, ok := object["data"].(string); ok {
		data = []string{str}
	}

	for _, str := range data {
		if ethutil.IsHex(str) {
			str = str[2:]

			if len(str) != 64 {
				str = ethutil.LeftPadString(str, 64)
			}
		} else {
			str = ethutil.Bytes2Hex(ethutil.LeftPadBytes(ethutil.Big(str).Bytes(), 32))
		}

		dataStr += str
	}
	object["data"] = dataStr

	conv := make(map[string]string)
	for key, value := range object {
		if v, ok := value.(string); ok {
			conv[key] = v
		}
	}

	return conv
}