BlockFilterArgs
This commit is contained in:
parent
2788fb4ce5
commit
9f84c78eb5
51
rpc/api.go
51
rpc/api.go
|
@ -471,42 +471,29 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
||||||
func toFilterOptions(options *BlockFilterArgs) *core.FilterOptions {
|
func toFilterOptions(options *BlockFilterArgs) *core.FilterOptions {
|
||||||
var opts core.FilterOptions
|
var opts core.FilterOptions
|
||||||
|
|
||||||
// Convert optional address slice/string to byte slice
|
opts.Address = cAddress(options.Address)
|
||||||
if str, ok := options.Address.(string); ok {
|
opts.Topics = cTopics(options.Topics)
|
||||||
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.Earliest = options.Earliest
|
opts.Earliest = options.Earliest
|
||||||
opts.Latest = options.Latest
|
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
|
return &opts
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func cAddress(a []string) []common.Address {
|
||||||
Work() chan<- *types.Block
|
bslice := make([]common.Address, len(a))
|
||||||
SetWorkCh(chan<- Work)
|
for i, addr := range a {
|
||||||
Stop()
|
bslice[i] = common.HexToAddress(addr)
|
||||||
Start()
|
}
|
||||||
Rate() uint64
|
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
|
||||||
|
}
|
||||||
|
|
116
rpc/args.go
116
rpc/args.go
|
@ -4,12 +4,17 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
// "errors"
|
// "errors"
|
||||||
// "fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultLogLimit = 100
|
||||||
|
defaultLogOffset = 0
|
||||||
|
)
|
||||||
|
|
||||||
func blockHeightFromJson(msg json.RawMessage, number *int64) error {
|
func blockHeightFromJson(msg json.RawMessage, number *int64) error {
|
||||||
var raw interface{}
|
var raw interface{}
|
||||||
if err := json.Unmarshal(msg, &raw); err != nil {
|
if err := json.Unmarshal(msg, &raw); err != nil {
|
||||||
|
@ -483,20 +488,20 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
|
||||||
type BlockFilterArgs struct {
|
type BlockFilterArgs struct {
|
||||||
Earliest int64
|
Earliest int64
|
||||||
Latest int64
|
Latest int64
|
||||||
Address interface{}
|
Address []string
|
||||||
Topics []interface{}
|
Topics [][]string
|
||||||
Skip int
|
Skip int
|
||||||
Max int
|
Max int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
|
func (args *BlockFilterArgs) UnmarshalJSON(b []byte) (err error) {
|
||||||
var obj []struct {
|
var obj []struct {
|
||||||
FromBlock interface{} `json:"fromBlock"`
|
FromBlock interface{} `json:"fromBlock"`
|
||||||
ToBlock interface{} `json:"toBlock"`
|
ToBlock interface{} `json:"toBlock"`
|
||||||
Limit interface{} `json:"limit"`
|
Limit interface{} `json:"limit"`
|
||||||
Offset interface{} `json:"offset"`
|
Offset interface{} `json:"offset"`
|
||||||
Address string `json:"address"`
|
Address interface{} `json:"address"`
|
||||||
Topics []interface{} `json:"topics"`
|
Topics interface{} `json:"topics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = json.Unmarshal(b, &obj); err != nil {
|
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))
|
// return NewDecodeParamError(fmt.Sprintf("ToBlock %v", err))
|
||||||
|
|
||||||
var num int64
|
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 {
|
if num < 0 {
|
||||||
args.Earliest = -1 //latest block
|
args.Earliest = -1 //latest block
|
||||||
} else {
|
} else {
|
||||||
args.Earliest = num
|
args.Earliest = num
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := blockHeight(obj[0].ToBlock, &num); err != nil {
|
// if blank than latest
|
||||||
return err
|
if obj[0].ToBlock == nil {
|
||||||
|
num = -1
|
||||||
|
} else {
|
||||||
|
if err := blockHeight(obj[0].ToBlock, &num); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
args.Latest = num
|
args.Latest = num
|
||||||
|
|
||||||
if err := numString(obj[0].Limit, &num); err != nil {
|
if obj[0].Limit == nil {
|
||||||
return err
|
num = defaultLogLimit
|
||||||
|
} else {
|
||||||
|
if err := numString(obj[0].Limit, &num); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
args.Max = int(num)
|
args.Max = int(num)
|
||||||
|
|
||||||
if err := numString(obj[0].Offset, &num); err != nil {
|
if obj[0].Offset == nil {
|
||||||
return err
|
num = defaultLogOffset
|
||||||
|
} else {
|
||||||
|
if err := numString(obj[0].Offset, &num); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
args.Skip = int(num)
|
args.Skip = int(num)
|
||||||
|
|
||||||
args.Address = obj[0].Address
|
if obj[0].Address != nil {
|
||||||
args.Topics = obj[0].Topics
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
214
rpc/args_test.go
214
rpc/args_test.go
|
@ -804,14 +804,23 @@ func TestBlockFilterArgs(t *testing.T) {
|
||||||
"limit": "0x3",
|
"limit": "0x3",
|
||||||
"offset": "0x0",
|
"offset": "0x0",
|
||||||
"address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
|
"address": "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8",
|
||||||
"topics": ["0x12341234"]}]`
|
"topics":
|
||||||
|
[
|
||||||
|
["0xAA", "0xBB"],
|
||||||
|
["0xCC", "0xDD"]
|
||||||
|
]
|
||||||
|
}]`
|
||||||
|
|
||||||
expected := new(BlockFilterArgs)
|
expected := new(BlockFilterArgs)
|
||||||
expected.Earliest = 1
|
expected.Earliest = 1
|
||||||
expected.Latest = 2
|
expected.Latest = 2
|
||||||
expected.Max = 3
|
expected.Max = 3
|
||||||
expected.Skip = 0
|
expected.Skip = 0
|
||||||
expected.Address = "0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"
|
expected.Address = []string{"0xd5677cf67b5aa051bb40496e68ad359eb97cfbf8"}
|
||||||
// expected.Topics = []string{"0x12341234"}
|
expected.Topics = [][]string{
|
||||||
|
[]string{"0xAA", "0xBB"},
|
||||||
|
[]string{"0xCC", "0xDD"},
|
||||||
|
}
|
||||||
|
|
||||||
args := new(BlockFilterArgs)
|
args := new(BlockFilterArgs)
|
||||||
if err := json.Unmarshal([]byte(input), &args); err != nil {
|
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)
|
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)
|
t.Errorf("Address shoud be %#v but is %#v", expected.Address, args.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if expected.Topics != args.Topics {
|
if expected.Topics[0][0] != args.Topics[0][0] {
|
||||||
// t.Errorf("Topic shoud be %#v but is %#v", expected.Topic, args.Topic)
|
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) {
|
func TestBlockFilterArgsWords(t *testing.T) {
|
||||||
t.Skip()
|
|
||||||
input := `[{
|
input := `[{
|
||||||
"fromBlock": "latest",
|
"fromBlock": "latest",
|
||||||
"toBlock": "pending"
|
"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 := `[{
|
input := `[{
|
||||||
"fromBlock": true,
|
"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)
|
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) {
|
func TestDbArgs(t *testing.T) {
|
||||||
input := `["testDB","myKey","0xbeef"]`
|
input := `["testDB","myKey","0xbeef"]`
|
||||||
expected := new(DbArgs)
|
expected := new(DbArgs)
|
||||||
|
|
Loading…
Reference in New Issue