Bläddra i källkod

Merge branch 'rpcfrontier' into develop

obscuren 10 år sedan
förälder
incheckning
38c7c589e4
11 ändrade filer med 629 tillägg och 728 borttagningar
  1. 1 1
      core/filter.go
  2. 3 1
      event/filter/eth_filter.go
  3. 176 560
      rpc/api.go
  4. 32 32
      rpc/api_test.go
  5. 18 8
      rpc/args.go
  6. 16 16
      rpc/args_test.go
  7. 8 8
      rpc/http.go
  8. 41 0
      rpc/messages_test.go
  9. 26 0
      rpc/responses.go
  10. 0 86
      rpc/util.go
  11. 308 16
      xeth/xeth.go

+ 1 - 1
core/filter.go

@@ -46,7 +46,7 @@ func NewFilter(eth Backend) *Filter {
 
 // SetOptions copies the filter options to the filter it self. The reason for this "silly" copy
 // is simply because named arguments in this case is extremely nice and readable.
-func (self *Filter) SetOptions(options FilterOptions) {
+func (self *Filter) SetOptions(options *FilterOptions) {
 	self.earliest = options.Earliest
 	self.latest = options.Latest
 	self.skip = options.Skip

+ 3 - 1
event/filter/eth_filter.go

@@ -48,7 +48,9 @@ func (self *FilterManager) InstallFilter(filter *core.Filter) (id int) {
 func (self *FilterManager) UninstallFilter(id int) {
 	self.filterMu.Lock()
 	defer self.filterMu.Unlock()
-	delete(self.filters, id)
+	if _, ok := self.filters[id]; ok {
+		delete(self.filters, id)
+	}
 }
 
 // GetFilter retrieves a filter installed using InstallFilter.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 176 - 560
rpc/api.go


+ 32 - 32
rpc/api_test.go

@@ -2,9 +2,9 @@ package rpc
 
 import (
 	"encoding/json"
-	"sync"
+	// "sync"
 	"testing"
-	"time"
+	// "time"
 )
 
 func TestWeb3Sha3(t *testing.T) {
@@ -24,33 +24,33 @@ func TestWeb3Sha3(t *testing.T) {
 	}
 }
 
-func TestFilterClose(t *testing.T) {
-	t.Skip()
-	api := &EthereumApi{
-		logs:     make(map[int]*logFilter),
-		messages: make(map[int]*whisperFilter),
-		quit:     make(chan struct{}),
-	}
-
-	filterTickerTime = 1
-	api.logs[0] = &logFilter{}
-	api.messages[0] = &whisperFilter{}
-	var wg sync.WaitGroup
-	wg.Add(1)
-	go api.start()
-	go func() {
-		select {
-		case <-time.After(500 * time.Millisecond):
-			api.stop()
-			wg.Done()
-		}
-	}()
-	wg.Wait()
-	if len(api.logs) != 0 {
-		t.Error("expected logs to be empty")
-	}
-
-	if len(api.messages) != 0 {
-		t.Error("expected messages to be empty")
-	}
-}
+// func TestFilterClose(t *testing.T) {
+// 	t.Skip()
+// 	api := &EthereumApi{
+// 		logs:     make(map[int]*logFilter),
+// 		messages: make(map[int]*whisperFilter),
+// 		quit:     make(chan struct{}),
+// 	}
+
+// 	filterTickerTime = 1
+// 	api.logs[0] = &logFilter{}
+// 	api.messages[0] = &whisperFilter{}
+// 	var wg sync.WaitGroup
+// 	wg.Add(1)
+// 	go api.start()
+// 	go func() {
+// 		select {
+// 		case <-time.After(500 * time.Millisecond):
+// 			api.stop()
+// 			wg.Done()
+// 		}
+// 	}()
+// 	wg.Wait()
+// 	if len(api.logs) != 0 {
+// 		t.Error("expected logs to be empty")
+// 	}
+
+// 	if len(api.messages) != 0 {
+// 		t.Error("expected messages to be empty")
+// 	}
+// }

+ 18 - 8
rpc/args.go

@@ -35,8 +35,8 @@ func blockAge(raw interface{}, number *int64) (err error) {
 }
 
 type GetBlockByHashArgs struct {
-	BlockHash    string
-	Transactions bool
+	BlockHash  string
+	IncludeTxs bool
 }
 
 func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) {
@@ -57,15 +57,15 @@ func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) {
 	args.BlockHash = argstr
 
 	if len(obj) > 1 {
-		args.Transactions = obj[1].(bool)
+		args.IncludeTxs = obj[1].(bool)
 	}
 
 	return nil
 }
 
 type GetBlockByNumberArgs struct {
-	BlockNumber  int64
-	Transactions bool
+	BlockNumber int64
+	IncludeTxs  bool
 }
 
 func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
@@ -86,7 +86,7 @@ func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
 	}
 
 	if len(obj) > 1 {
-		args.Transactions = obj[1].(bool)
+		args.IncludeTxs = obj[1].(bool)
 	}
 
 	return nil
@@ -433,7 +433,7 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
-type FilterOptions struct {
+type BlockFilterArgs struct {
 	Earliest int64
 	Latest   int64
 	Address  interface{}
@@ -442,7 +442,7 @@ type FilterOptions struct {
 	Max      int
 }
 
-func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
+func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []struct {
 		FromBlock interface{}   `json:"fromBlock"`
 		ToBlock   interface{}   `json:"toBlock"`
@@ -609,6 +609,16 @@ func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
+func (args *FilterStringArgs) requirements() error {
+	switch args.Word {
+	case "latest", "pending":
+		break
+	default:
+		return NewValidationError("Word", "Must be `latest` or `pending`")
+	}
+	return nil
+}
+
 type FilterIdArgs struct {
 	Id int
 }

+ 16 - 16
rpc/args_test.go

@@ -82,7 +82,7 @@ func TestGetBlockByHashArgs(t *testing.T) {
 	input := `["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true]`
 	expected := new(GetBlockByHashArgs)
 	expected.BlockHash = "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
-	expected.Transactions = true
+	expected.IncludeTxs = true
 
 	args := new(GetBlockByHashArgs)
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
@@ -93,8 +93,8 @@ func TestGetBlockByHashArgs(t *testing.T) {
 		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)
+	if args.IncludeTxs != expected.IncludeTxs {
+		t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs)
 	}
 }
 
@@ -112,7 +112,7 @@ func TestGetBlockByNumberArgs(t *testing.T) {
 	input := `["0x1b4", false]`
 	expected := new(GetBlockByNumberArgs)
 	expected.BlockNumber = 436
-	expected.Transactions = false
+	expected.IncludeTxs = false
 
 	args := new(GetBlockByNumberArgs)
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
@@ -123,8 +123,8 @@ func TestGetBlockByNumberArgs(t *testing.T) {
 		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)
+	if args.IncludeTxs != expected.IncludeTxs {
+		t.Errorf("IncludeTxs should be %v but is %v", expected.IncludeTxs, args.IncludeTxs)
 	}
 }
 
@@ -388,7 +388,7 @@ func TestGetDataEmptyArgs(t *testing.T) {
 	}
 }
 
-func TestFilterOptions(t *testing.T) {
+func TestBlockFilterArgs(t *testing.T) {
 	input := `[{
   "fromBlock": "0x1",
   "toBlock": "0x2",
@@ -396,7 +396,7 @@ func TestFilterOptions(t *testing.T) {
   "offset": "0x0",
   "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
   "topics": ["0x12341234"]}]`
-	expected := new(FilterOptions)
+	expected := new(BlockFilterArgs)
 	expected.Earliest = 1
 	expected.Latest = 2
 	expected.Max = 3
@@ -404,7 +404,7 @@ func TestFilterOptions(t *testing.T) {
 	expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
 	// expected.Topics = []string{"0x12341234"}
 
-	args := new(FilterOptions)
+	args := new(BlockFilterArgs)
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
 		t.Error(err)
 	}
@@ -434,16 +434,16 @@ func TestFilterOptions(t *testing.T) {
 	// }
 }
 
-func TestFilterOptionsWords(t *testing.T) {
+func TestBlockFilterArgsWords(t *testing.T) {
 	input := `[{
   "fromBlock": "latest",
   "toBlock": "pending"
   }]`
-	expected := new(FilterOptions)
+	expected := new(BlockFilterArgs)
 	expected.Earliest = 0
 	expected.Latest = -1
 
-	args := new(FilterOptions)
+	args := new(BlockFilterArgs)
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
 		t.Error(err)
 	}
@@ -457,13 +457,13 @@ func TestFilterOptionsWords(t *testing.T) {
 	}
 }
 
-func TestFilterOptionsNums(t *testing.T) {
+func TestBlockFilterArgsNums(t *testing.T) {
 	input := `[{
   "fromBlock": 2,
   "toBlock": 3
   }]`
 
-	args := new(FilterOptions)
+	args := new(BlockFilterArgs)
 	err := json.Unmarshal([]byte(input), &args)
 	switch err.(type) {
 	case *DecodeParamError:
@@ -474,10 +474,10 @@ func TestFilterOptionsNums(t *testing.T) {
 
 }
 
-func TestFilterOptionsEmptyArgs(t *testing.T) {
+func TestBlockFilterArgsEmptyArgs(t *testing.T) {
 	input := `[]`
 
-	args := new(FilterOptions)
+	args := new(BlockFilterArgs)
 	err := json.Unmarshal([]byte(input), &args)
 	if err == nil {
 		t.Error("Expected error but didn't get one")

+ 8 - 8
rpc/http.go

@@ -10,7 +10,7 @@ import (
 	"github.com/ethereum/go-ethereum/xeth"
 )
 
-var rpchttplogger = logger.NewLogger("RPC-HTTP")
+var rpclogger = logger.NewLogger("RPC")
 
 const (
 	jsonrpcver       = "2.0"
@@ -28,7 +28,7 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 		// Limit request size to resist DoS
 		if req.ContentLength > maxSizeReqLength {
 			jsonerr := &RpcErrorObject{-32700, "Request too large"}
-			Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
+			send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 			return
 		}
 
@@ -37,14 +37,14 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 		body, err := ioutil.ReadAll(req.Body)
 		if err != nil {
 			jsonerr := &RpcErrorObject{-32700, "Could not read request body"}
-			Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
+			send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 		}
 
 		// Try to parse the request as a single
 		var reqSingle RpcRequest
 		if err := json.Unmarshal(body, &reqSingle); err == nil {
 			response := RpcResponse(api, &reqSingle)
-			Send(w, &response)
+			send(w, &response)
 			return
 		}
 
@@ -57,13 +57,13 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 				response := RpcResponse(api, &request)
 				resBatch[i] = response
 			}
-			Send(w, resBatch)
+			send(w, resBatch)
 			return
 		}
 
 		// Not a batch or single request, error
 		jsonerr := &RpcErrorObject{-32600, "Could not decode request"}
-		Send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
+		send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
 	})
 }
 
@@ -84,11 +84,11 @@ func RpcResponse(api *EthereumApi, request *RpcRequest) *interface{} {
 		response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
 	}
 
-	rpchttplogger.DebugDetailf("Generated response: %T %s", response, response)
+	rpclogger.DebugDetailf("Generated response: %T %s", response, response)
 	return &response
 }
 
-func Send(writer io.Writer, v interface{}) (n int, err error) {
+func send(writer io.Writer, v interface{}) (n int, err error) {
 	var payload []byte
 	payload, err = json.MarshalIndent(v, "", "\t")
 	if err != nil {

+ 41 - 0
rpc/messages_test.go

@@ -0,0 +1,41 @@
+package rpc
+
+import (
+	"testing"
+)
+
+func TestInsufficientParamsError(t *testing.T) {
+	err := NewInsufficientParamsError(0, 1)
+	expected := "insufficient params, want 1 have 0"
+
+	if err.Error() != expected {
+		t.Error(err.Error())
+	}
+}
+
+func TestNotImplementedError(t *testing.T) {
+	err := NewNotImplementedError("foo")
+	expected := "foo method not implemented"
+
+	if err.Error() != expected {
+		t.Error(err.Error())
+	}
+}
+
+func TestDecodeParamError(t *testing.T) {
+	err := NewDecodeParamError("foo")
+	expected := "could not decode, foo"
+
+	if err.Error() != expected {
+		t.Error(err.Error())
+	}
+}
+
+func TestValidationError(t *testing.T) {
+	err := NewValidationError("foo", "should be `bar`")
+	expected := "foo not valid, should be `bar`"
+
+	if err.Error() != expected {
+		t.Error(err.Error())
+	}
+}

+ 26 - 0
rpc/responses.go

@@ -7,6 +7,7 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/state"
 )
 
 type BlockRes struct {
@@ -211,3 +212,28 @@ type FilterWhisperRes struct {
 	Payload    string `json:"payload"`
 	WorkProved string `json:"workProved"`
 }
+
+type LogRes struct {
+	Address string   `json:"address"`
+	Topic   []string `json:"topic"`
+	Data    string   `json:"data"`
+	Number  uint64   `json:"number"`
+}
+
+func NewLogsRes(logs state.Logs) (ls []LogRes) {
+	ls = make([]LogRes, len(logs))
+
+	for i, log := range logs {
+		var l LogRes
+		l.Topic = make([]string, len(log.Topics()))
+		l.Address = common.ToHex(log.Address())
+		l.Data = common.ToHex(log.Data())
+		l.Number = log.Number()
+		for j, topic := range log.Topics() {
+			l.Topic[j] = common.ToHex(topic)
+		}
+		ls[i] = l
+	}
+
+	return
+}

+ 0 - 86
rpc/util.go

@@ -1,86 +0,0 @@
-/*
-	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/>.
-*/
-package rpc
-
-import (
-	"time"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/state"
-	"github.com/ethereum/go-ethereum/xeth"
-)
-
-var rpclogger = logger.NewLogger("RPC")
-
-type Log struct {
-	Address string   `json:"address"`
-	Topic   []string `json:"topic"`
-	Data    string   `json:"data"`
-	Number  uint64   `json:"number"`
-}
-
-func toLogs(logs state.Logs) (ls []Log) {
-	ls = make([]Log, len(logs))
-
-	for i, log := range logs {
-		var l Log
-		l.Topic = make([]string, len(log.Topics()))
-		l.Address = common.ToHex(log.Address())
-		l.Data = common.ToHex(log.Data())
-		l.Number = log.Number()
-		for j, topic := range log.Topics() {
-			l.Topic[j] = common.ToHex(topic)
-		}
-		ls[i] = l
-	}
-
-	return
-}
-
-type whisperFilter struct {
-	messages []xeth.WhisperMessage
-	timeout  time.Time
-	id       int
-}
-
-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
-	id      int
-}
-
-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
-}

+ 308 - 16
xeth/xeth.go

@@ -6,6 +6,8 @@ import (
 	"encoding/json"
 	"fmt"
 	"math/big"
+	"sync"
+	"time"
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
@@ -13,13 +15,19 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/event/filter"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/state"
 	"github.com/ethereum/go-ethereum/whisper"
 )
 
-var pipelogger = logger.NewLogger("XETH")
+var (
+	pipelogger       = logger.NewLogger("XETH")
+	filterTickerTime = 5 * time.Minute
+	defaultGasPrice  = big.NewInt(10000000000000) //150000000000
+	defaultGas       = big.NewInt(90000)          //500000
+)
 
 // to resolve the import cycle
 type Backend interface {
@@ -62,6 +70,13 @@ type Frontend interface {
 	ConfirmTransaction(tx *types.Transaction) bool
 }
 
+// dummyFrontend is a non-interactive frontend that allows all
+// transactions but cannot not unlock any keys.
+type dummyFrontend struct{}
+
+func (dummyFrontend) UnlockAccount([]byte) bool                  { return false }
+func (dummyFrontend) ConfirmTransaction(*types.Transaction) bool { return true }
+
 type XEth struct {
 	eth            Backend
 	blockProcessor *core.BlockProcessor
@@ -71,14 +86,19 @@ type XEth struct {
 	whisper        *Whisper
 
 	frontend Frontend
-}
 
-// dummyFrontend is a non-interactive frontend that allows all
-// transactions but cannot not unlock any keys.
-type dummyFrontend struct{}
+	quit          chan struct{}
+	filterManager *filter.FilterManager
 
-func (dummyFrontend) UnlockAccount([]byte) bool                  { return false }
-func (dummyFrontend) ConfirmTransaction(*types.Transaction) bool { return true }
+	logMut sync.RWMutex
+	logs   map[int]*logFilter
+
+	messagesMut sync.RWMutex
+	messages    map[int]*whisperFilter
+
+	// regmut   sync.Mutex
+	// register map[string][]*interface{} // TODO improve return type
+}
 
 // New creates an XEth that uses the given frontend.
 // If a nil Frontend is provided, a default frontend which
@@ -90,15 +110,76 @@ func New(eth Backend, frontend Frontend) *XEth {
 		chainManager:   eth.ChainManager(),
 		accountManager: eth.AccountManager(),
 		whisper:        NewWhisper(eth.Whisper()),
+		quit:           make(chan struct{}),
+		filterManager:  filter.NewFilterManager(eth.EventMux()),
 		frontend:       frontend,
+		logs:           make(map[int]*logFilter),
+		messages:       make(map[int]*whisperFilter),
 	}
 	if frontend == nil {
 		xeth.frontend = dummyFrontend{}
 	}
 	xeth.state = NewState(xeth, xeth.chainManager.TransState())
+	go xeth.start()
+	go xeth.filterManager.Start()
+
 	return xeth
 }
 
+func (self *XEth) start() {
+	timer := time.NewTicker(2 * time.Second)
+done:
+	for {
+		select {
+		case <-timer.C:
+			self.logMut.Lock()
+			self.messagesMut.Lock()
+			for id, filter := range self.logs {
+				if time.Since(filter.timeout) > filterTickerTime {
+					self.filterManager.UninstallFilter(id)
+					delete(self.logs, id)
+				}
+			}
+
+			for id, filter := range self.messages {
+				if time.Since(filter.timeout) > filterTickerTime {
+					self.Whisper().Unwatch(id)
+					delete(self.messages, id)
+				}
+			}
+			self.messagesMut.Unlock()
+			self.logMut.Unlock()
+		case <-self.quit:
+			break done
+		}
+	}
+}
+
+func (self *XEth) stop() {
+	close(self.quit)
+}
+
+func (self *XEth) DefaultGas() *big.Int      { return defaultGas }
+func (self *XEth) DefaultGasPrice() *big.Int { return defaultGasPrice }
+
+func (self *XEth) AtStateNum(num int64) *XEth {
+	chain := self.Backend().ChainManager()
+	var block *types.Block
+
+	if num < 0 {
+		num = chain.CurrentBlock().Number().Int64() + num + 1
+	}
+	block = chain.GetBlockByNumber(uint64(num))
+
+	var st *state.StateDB
+	if block != nil {
+		st = state.New(block.Root(), self.Backend().StateDb())
+	} else {
+		st = chain.State()
+	}
+	return self.WithState(st)
+}
+
 func (self *XEth) Backend() Backend { return self.eth }
 func (self *XEth) WithState(statedb *state.StateDB) *XEth {
 	xeth := &XEth{
@@ -241,6 +322,157 @@ func (self *XEth) SecretToAddress(key string) string {
 	return common.ToHex(pair.Address())
 }
 
+func (self *XEth) RegisterFilter(args *core.FilterOptions) int {
+	var id int
+	filter := core.NewFilter(self.Backend())
+	filter.SetOptions(args)
+	filter.LogsCallback = func(logs state.Logs) {
+		self.logMut.Lock()
+		defer self.logMut.Unlock()
+
+		self.logs[id].add(logs...)
+	}
+	id = self.filterManager.InstallFilter(filter)
+	self.logs[id] = &logFilter{timeout: time.Now()}
+
+	return id
+}
+
+func (self *XEth) UninstallFilter(id int) bool {
+	if _, ok := self.logs[id]; ok {
+		delete(self.logs, id)
+		self.filterManager.UninstallFilter(id)
+		return true
+	}
+
+	return false
+}
+
+func (self *XEth) NewFilterString(word string) int {
+	var id int
+	filter := core.NewFilter(self.Backend())
+
+	switch word {
+	case "pending":
+		filter.PendingCallback = func(tx *types.Transaction) {
+			self.logMut.Lock()
+			defer self.logMut.Unlock()
+
+			self.logs[id].add(&state.StateLog{})
+		}
+	case "latest":
+		filter.BlockCallback = func(block *types.Block, logs state.Logs) {
+			self.logMut.Lock()
+			defer self.logMut.Unlock()
+
+			for _, log := range logs {
+				self.logs[id].add(log)
+			}
+			self.logs[id].add(&state.StateLog{})
+		}
+	}
+
+	id = self.filterManager.InstallFilter(filter)
+	self.logs[id] = &logFilter{timeout: time.Now()}
+
+	return id
+}
+
+func (self *XEth) FilterChanged(id int) state.Logs {
+	self.logMut.Lock()
+	defer self.logMut.Unlock()
+
+	if self.logs[id] != nil {
+		return self.logs[id].get()
+	}
+
+	return nil
+}
+
+func (self *XEth) Logs(id int) state.Logs {
+	self.logMut.Lock()
+	defer self.logMut.Unlock()
+
+	filter := self.filterManager.GetFilter(id)
+	if filter != nil {
+		return filter.Find()
+	}
+
+	return nil
+}
+
+func (self *XEth) AllLogs(args *core.FilterOptions) state.Logs {
+	filter := core.NewFilter(self.Backend())
+	filter.SetOptions(args)
+
+	return filter.Find()
+}
+
+func (p *XEth) NewWhisperFilter(opts *Options) int {
+	var id int
+	opts.Fn = func(msg WhisperMessage) {
+		p.messagesMut.Lock()
+		defer p.messagesMut.Unlock()
+		p.messages[id].add(msg) // = append(p.messages[id], msg)
+	}
+	id = p.Whisper().Watch(opts)
+	p.messages[id] = &whisperFilter{timeout: time.Now()}
+	return id
+}
+
+func (p *XEth) UninstallWhisperFilter(id int) bool {
+	if _, ok := p.messages[id]; ok {
+		delete(p.messages, id)
+		return true
+	}
+
+	return false
+}
+
+func (self *XEth) MessagesChanged(id int) []WhisperMessage {
+	self.messagesMut.Lock()
+	defer self.messagesMut.Unlock()
+
+	if self.messages[id] != nil {
+		return self.messages[id].get()
+	}
+
+	return nil
+}
+
+// func (self *XEth) Register(args string) bool {
+// 	self.regmut.Lock()
+// 	defer self.regmut.Unlock()
+
+// 	if _, ok := self.register[args]; ok {
+// 		self.register[args] = nil // register with empty
+// 	}
+// 	return true
+// }
+
+// func (self *XEth) Unregister(args string) bool {
+// 	self.regmut.Lock()
+// 	defer self.regmut.Unlock()
+
+// 	if _, ok := self.register[args]; ok {
+// 		delete(self.register, args)
+// 		return true
+// 	}
+
+// 	return false
+// }
+
+// // TODO improve return type
+// func (self *XEth) PullWatchTx(args string) []*interface{} {
+// 	self.regmut.Lock()
+// 	defer self.regmut.Unlock()
+
+// 	txs := self.register[args]
+// 	self.register[args] = nil
+
+// 	return txs
+// }
+
 type KeyVal struct {
 	Key   string `json:"key"`
 	Value string `json:"value"`
@@ -298,11 +530,6 @@ func (self *XEth) PushTx(encodedTx string) (string, error) {
 	return common.ToHex(tx.Hash()), nil
 }
 
-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{
@@ -333,12 +560,44 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
 		from             []byte
 		to               []byte
 		value            = common.NewValue(valueStr)
-		gas              = common.NewValue(gasStr)
-		price            = common.NewValue(gasPriceStr)
+		gas              = common.Big(gasStr)
+		price            = common.Big(gasPriceStr)
 		data             []byte
 		contractCreation bool
 	)
 
+	// 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(common.FromHex(args.From))
+		if account != nil {
+			if account.Unlocked() {
+				if !unlockAccount(account) {
+					return
+				}
+			}
+
+			result, _ := account.Transact(common.FromHex(args.To), common.FromHex(args.Value), common.FromHex(args.Gas), common.FromHex(args.GasPrice), common.FromHex(args.Data))
+			if len(result) > 0 {
+				*reply = common.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
+	// common.Value conversions later on
+	if gas.Cmp(big.NewInt(0)) == 0 {
+		gas = defaultGas
+	}
+
+	if price.Cmp(big.NewInt(0)) == 0 {
+		price = defaultGasPrice
+	}
+
 	from = common.FromHex(fromStr)
 	data = common.FromHex(codeStr)
 	to = common.FromHex(toStr)
@@ -348,9 +607,9 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
 
 	var tx *types.Transaction
 	if contractCreation {
-		tx = types.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), data)
+		tx = types.NewContractCreationTx(value.BigInt(), gas, price, data)
 	} else {
-		tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
+		tx = types.NewTransactionMessage(to, value.BigInt(), gas, price, data)
 	}
 
 	state := self.chainManager.TxState()
@@ -411,3 +670,36 @@ func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
 func (m callmsg) Gas() *big.Int      { return m.gas }
 func (m callmsg) Value() *big.Int    { return m.value }
 func (m callmsg) Data() []byte       { return m.data }
+
+type whisperFilter struct {
+	messages []WhisperMessage
+	timeout  time.Time
+	id       int
+}
+
+func (w *whisperFilter) add(msgs ...WhisperMessage) {
+	w.messages = append(w.messages, msgs...)
+}
+func (w *whisperFilter) get() []WhisperMessage {
+	w.timeout = time.Now()
+	tmp := w.messages
+	w.messages = nil
+	return tmp
+}
+
+type logFilter struct {
+	logs    state.Logs
+	timeout time.Time
+	id      int
+}
+
+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
+}

Vissa filer visades inte eftersom för många filer har ändrats