diff --git a/rpc/api.go b/rpc/api.go
index 76fa9b9df6b6be4c153bc63aca139eaad9035b2d..534b6fc5d499c7f7d2b297069bf7d53cbf9c5ebe 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -471,42 +471,29 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
 func toFilterOptions(options *BlockFilterArgs) *core.FilterOptions {
 	var opts core.FilterOptions
 
-	// Convert optional address slice/string to byte slice
-	if str, ok := options.Address.(string); ok {
-		opts.Address = []common.Address{common.HexToAddress(str)}
-	} else if slice, ok := options.Address.([]interface{}); ok {
-		bslice := make([]common.Address, len(slice))
-		for i, addr := range slice {
-			if saddr, ok := addr.(string); ok {
-				bslice[i] = common.HexToAddress(saddr)
-			}
-		}
-		opts.Address = bslice
-	}
+	opts.Address = cAddress(options.Address)
+	opts.Topics = cTopics(options.Topics)
 
 	opts.Earliest = options.Earliest
 	opts.Latest = options.Latest
 
-	topics := make([][]common.Hash, len(options.Topics))
-	for i, topicDat := range options.Topics {
-		if slice, ok := topicDat.([]interface{}); ok {
-			topics[i] = make([]common.Hash, len(slice))
-			for j, topic := range slice {
-				topics[i][j] = common.HexToHash(topic.(string))
-			}
-		} else if str, ok := topicDat.(string); ok {
-			topics[i] = []common.Hash{common.HexToHash(str)}
-		}
-	}
-	opts.Topics = topics
-
 	return &opts
 }
 
-/*
-	Work() chan<- *types.Block
-	SetWorkCh(chan<- Work)
-	Stop()
-	Start()
-	Rate() uint64
-*/
+func cAddress(a []string) []common.Address {
+	bslice := make([]common.Address, len(a))
+	for i, addr := range a {
+		bslice[i] = common.HexToAddress(addr)
+	}
+	return bslice
+}
+
+func cTopics(t [][]string) [][]common.Hash {
+	topics := make([][]common.Hash, len(t))
+	for i, iv := range t {
+		for j, jv := range iv {
+			topics[i][j] = common.HexToHash(jv)
+		}
+	}
+	return topics
+}
diff --git a/rpc/args.go b/rpc/args.go
index 78cbca5a98b14d0095ab736161c71630dfe167da..a075f1a596b7bd9413af085c3bdbbfcb0511c105 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -4,12 +4,17 @@ import (
 	"bytes"
 	"encoding/json"
 	// "errors"
-	// "fmt"
+	"fmt"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
 )
 
+const (
+	defaultLogLimit  = 100
+	defaultLogOffset = 0
+)
+
 func blockHeightFromJson(msg json.RawMessage, number *int64) error {
 	var raw interface{}
 	if err := json.Unmarshal(msg, &raw); err != nil {
@@ -483,20 +488,20 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
 type BlockFilterArgs struct {
 	Earliest int64
 	Latest   int64
-	Address  interface{}
-	Topics   []interface{}
+	Address  []string
+	Topics   [][]string
 	Skip     int
 	Max      int
 }
 
 func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []struct {
-		FromBlock interface{}   `json:"fromBlock"`
-		ToBlock   interface{}   `json:"toBlock"`
-		Limit     interface{}   `json:"limit"`
-		Offset    interface{}   `json:"offset"`
-		Address   string        `json:"address"`
-		Topics    []interface{} `json:"topics"`
+		FromBlock interface{} `json:"fromBlock"`
+		ToBlock   interface{} `json:"toBlock"`
+		Limit     interface{} `json:"limit"`
+		Offset    interface{} `json:"offset"`
+		Address   interface{} `json:"address"`
+		Topics    interface{} `json:"topics"`
 	}
 
 	if err = json.Unmarshal(b, &obj); err != nil {
@@ -516,33 +521,104 @@ func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
 	// 	return NewDecodeParamError(fmt.Sprintf("ToBlock %v", err))
 
 	var num int64
-	if err := blockHeight(obj[0].FromBlock, &num); err != nil {
-		return err
+
+	// if blank then latest
+	if obj[0].FromBlock == nil {
+		num = -1
+	} else {
+		if err := blockHeight(obj[0].FromBlock, &num); err != nil {
+			return err
+		}
 	}
+	// if -2 or other "silly" number, use latest
 	if num < 0 {
 		args.Earliest = -1 //latest block
 	} else {
 		args.Earliest = num
 	}
 
-	if err := blockHeight(obj[0].ToBlock, &num); err != nil {
-		return err
+	// if blank than latest
+	if obj[0].ToBlock == nil {
+		num = -1
+	} else {
+		if err := blockHeight(obj[0].ToBlock, &num); err != nil {
+			return err
+		}
 	}
 	args.Latest = num
 
-	if err := numString(obj[0].Limit, &num); err != nil {
-		return err
+	if obj[0].Limit == nil {
+		num = defaultLogLimit
+	} else {
+		if err := numString(obj[0].Limit, &num); err != nil {
+			return err
+		}
 	}
 	args.Max = int(num)
 
-	if err := numString(obj[0].Offset, &num); err != nil {
-		return err
-
+	if obj[0].Offset == nil {
+		num = defaultLogOffset
+	} else {
+		if err := numString(obj[0].Offset, &num); err != nil {
+			return err
+		}
 	}
 	args.Skip = int(num)
 
-	args.Address = obj[0].Address
-	args.Topics = obj[0].Topics
+	if obj[0].Address != nil {
+		marg, ok := obj[0].Address.([]interface{})
+		if ok {
+			v := make([]string, len(marg))
+			for i, arg := range marg {
+				argstr, ok := arg.(string)
+				if !ok {
+					return NewInvalidTypeError(fmt.Sprintf("address[%d]", i), "is not a string")
+				}
+				v[i] = argstr
+			}
+			args.Address = v
+		} else {
+			argstr, ok := obj[0].Address.(string)
+			if ok {
+				v := make([]string, 1)
+				v[0] = argstr
+				args.Address = v
+			} else {
+				return NewInvalidTypeError("address", "is not a string or array")
+			}
+		}
+	}
+
+	if obj[0].Topics != nil {
+		other, ok := obj[0].Topics.([]interface{})
+		if ok {
+			topicdbl := make([][]string, len(other))
+			for i, iv := range other {
+				if argstr, ok := iv.(string); ok {
+					// Found a string, push into first element of array
+					topicsgl := make([]string, 1)
+					topicsgl[0] = argstr
+					topicdbl[i] = topicsgl
+				} else if argarray, ok := iv.([]interface{}); ok {
+					// Found an array of other
+					topicdbl[i] = make([]string, len(argarray))
+					for j, jv := range argarray {
+						if v, ok := jv.(string); ok {
+							topicdbl[i][j] = v
+						} else {
+							return NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", i, j), "is not a string")
+						}
+					}
+				} else {
+					return NewInvalidTypeError(fmt.Sprintf("topic[%d]", i), "not a string or array")
+				}
+			}
+			args.Topics = topicdbl
+			return nil
+		} else {
+			return NewInvalidTypeError("topic", "is not a string or array")
+		}
+	}
 
 	return nil
 }
diff --git a/rpc/args_test.go b/rpc/args_test.go
index cb1d1904b3f24669af42980ae6384132ee229c2e..602631b677455e6b58cb848c778d933143c358f3 100644
--- a/rpc/args_test.go
+++ b/rpc/args_test.go
@@ -804,14 +804,23 @@ func TestBlockFilterArgs(t *testing.T) {
   "limit": "0x3",
   "offset": "0x0",
   "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
-  "topics": ["0x12341234"]}]`
+  "topics":
+  [
+  	["0xAA", "0xBB"],
+  	["0xCC", "0xDD"]
+  ]
+  }]`
+
 	expected := new(BlockFilterArgs)
 	expected.Earliest = 1
 	expected.Latest = 2
 	expected.Max = 3
 	expected.Skip = 0
-	expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
-	// expected.Topics = []string{"0x12341234"}
+	expected.Address = []string{"0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"}
+	expected.Topics = [][]string{
+		[]string{"0xAA", "0xBB"},
+		[]string{"0xCC", "0xDD"},
+	}
 
 	args := new(BlockFilterArgs)
 	if err := json.Unmarshal([]byte(input), &args); err != nil {
@@ -834,17 +843,73 @@ func TestBlockFilterArgs(t *testing.T) {
 		t.Errorf("Skip shoud be %#v but is %#v", expected.Skip, args.Skip)
 	}
 
-	if expected.Address != args.Address {
+	if expected.Address[0] != args.Address[0] {
 		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)
-	// }
+	if expected.Topics[0][0] != args.Topics[0][0] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
+	if expected.Topics[0][1] != args.Topics[0][1] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
+	if expected.Topics[1][0] != args.Topics[1][0] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
+	if expected.Topics[1][1] != args.Topics[1][1] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
+
+}
+
+func TestBlockFilterArgsDefaults(t *testing.T) {
+	input := `[{
+  "address": ["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"],
+  "topics": ["0xAA","0xBB"]
+  }]`
+	expected := new(BlockFilterArgs)
+	expected.Earliest = -1
+	expected.Latest = -1
+	expected.Max = 100
+	expected.Skip = 0
+	expected.Address = []string{"0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"}
+	expected.Topics = [][]string{[]string{"0xAA"}, []string{"0xBB"}}
+
+	args := new(BlockFilterArgs)
+	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[0] != args.Address[0] {
+		t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
+	}
+
+	if expected.Topics[0][0] != args.Topics[0][0] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
+
+	if expected.Topics[1][0] != args.Topics[1][0] {
+		t.Errorf("Topics shoud be %#v but is %#v", expected.Topics, args.Topics)
+	}
 }
 
 func TestBlockFilterArgsWords(t *testing.T) {
-	t.Skip()
 	input := `[{
   "fromBlock": "latest",
   "toBlock": "pending"
@@ -867,10 +932,33 @@ func TestBlockFilterArgsWords(t *testing.T) {
 	}
 }
 
-func TestBlockFilterArgsBool(t *testing.T) {
+func TestBlockFilterArgsInvalid(t *testing.T) {
+	input := `{}`
+
+	args := new(BlockFilterArgs)
+	str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsFromBool(t *testing.T) {
 	input := `[{
   "fromBlock": true,
-  "toBlock": false
+  "toBlock": "pending"
+  }]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsToBool(t *testing.T) {
+	input := `[{
+  "fromBlock": "pending",
+  "toBlock": true
   }]`
 
 	args := new(BlockFilterArgs)
@@ -890,6 +978,112 @@ func TestBlockFilterArgsEmptyArgs(t *testing.T) {
 	}
 }
 
+func TestBlockFilterArgsLimitInvalid(t *testing.T) {
+	input := `[{"limit": false}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsOffsetInvalid(t *testing.T) {
+	input := `[{"offset": true}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsAddressInt(t *testing.T) {
+	input := `[{
+  "address": 1,
+  "topics": "0x12341234"}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsAddressSliceInt(t *testing.T) {
+	input := `[{
+  "address": [1],
+  "topics": "0x12341234"}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsTopicInt(t *testing.T) {
+	input := `[{
+  "address": ["0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"],
+  "topics": 1}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsTopicSliceInt(t *testing.T) {
+	input := `[{
+  "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
+  "topics": [1]}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsTopicSliceInt2(t *testing.T) {
+	input := `[{
+  "address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
+  "topics": ["0xAA", [1]]}]`
+
+	args := new(BlockFilterArgs)
+	str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args))
+	if len(str) > 0 {
+		t.Error(str)
+	}
+}
+
+func TestBlockFilterArgsTopicComplex(t *testing.T) {
+	input := `[{
+	"address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
+  "topics": ["0xAA", ["0xBB", "0xCC"]]
+  }]`
+
+	args := new(BlockFilterArgs)
+	if err := json.Unmarshal([]byte(input), &args); err != nil {
+		t.Error(err)
+		fmt.Printf("%v\n", args)
+		return
+	}
+
+	if args.Topics[0][0] != "0xAA" {
+		t.Errorf("Topic should be %s but is %s", "0xAA", args.Topics[0][0])
+	}
+
+	if args.Topics[1][0] != "0xBB" {
+		t.Errorf("Topic should be %s but is %s", "0xBB", args.Topics[0][0])
+	}
+
+	if args.Topics[1][1] != "0xCC" {
+		t.Errorf("Topic should be %s but is %s", "0xCC", args.Topics[0][0])
+	}
+}
+
 func TestDbArgs(t *testing.T) {
 	input := `["testDB","myKey","0xbeef"]`
 	expected := new(DbArgs)